Completed
Push — master ( b59571...1ee45e )
by thomas
55:12 queued 52:48
created

PublicKey   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 155
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 0%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 155
ccs 0
cts 76
cp 0
rs 10
c 1
b 0
f 0
wmc 19
lcom 1
cbo 4

10 Methods

Rating   Name   Duplication   Size   Complexity  
A verify() 0 4 1
A __construct() 0 15 4
A doEquals() 0 11 3
A equals() 0 5 1
A isCompressed() 0 4 1
A getResource() 0 4 1
A clonePubkey() 0 16 3
A tweakAdd() 0 12 2
A tweakMul() 0 12 2
A getBuffer() 0 4 1
1
<?php
2
3
namespace BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Key;
4
5
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Adapter\EcAdapter;
6
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Serializer\Key\PublicKeySerializer;
7
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\Key;
8
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\PublicKeyInterface;
9
use BitWasp\Bitcoin\Crypto\EcAdapter\Signature\SignatureInterface;
10
use BitWasp\Buffertools\Buffer;
11
use BitWasp\Buffertools\BufferInterface;
12
13
class PublicKey extends Key implements PublicKeyInterface
14
{
15
    /**
16
     * @var EcAdapter
17
     */
18
    private $ecAdapter;
19
20
    /**
21
     * @var bool|false
22
     */
23
    private $compressed;
24
25
    /**
26
     * @var resource
27
     */
28
    private $pubkey_t;
29
30
    /**
31
     * @param EcAdapter $ecAdapter
32
     * @param resource $secp256k1_pubkey_t
33
     * @param bool|false $compressed
34
     */
35
    public function __construct(EcAdapter $ecAdapter, $secp256k1_pubkey_t, $compressed = false)
36
    {
37
        if (!is_resource($secp256k1_pubkey_t) ||
38
            !get_resource_type($secp256k1_pubkey_t) === SECP256K1_TYPE_PUBKEY) {
39
            throw new \InvalidArgumentException('Secp256k1\Key\PublicKey expects ' . SECP256K1_TYPE_PUBKEY . ' resource');
40
        }
41
42
        if (false === is_bool($compressed)) {
43
            throw new \InvalidArgumentException('PublicKey: Compressed must be a boolean');
44
        }
45
46
        $this->ecAdapter = $ecAdapter;
47
        $this->pubkey_t = $secp256k1_pubkey_t;
48
        $this->compressed = $compressed;
49
    }
50
    
51
    /**
52
     * @param BufferInterface $msg32
53
     * @param SignatureInterface $signature
54
     * @return bool
55
     */
56
    public function verify(BufferInterface $msg32, SignatureInterface $signature)
57
    {
58
        return $this->ecAdapter->verify($msg32, $this, $signature);
59
    }
60
61
    /**
62
     * @param PublicKey $other
63
     * @return bool
64
     */
65
    private function doEquals(PublicKey $other)
66
    {
67
        $context = $this->ecAdapter->getContext();
68
        $pubA = '';
69
        $pubB = '';
70
        if (!(secp256k1_ec_pubkey_serialize($context, $pubA, $this->pubkey_t, $this->compressed) && secp256k1_ec_pubkey_serialize($context, $pubB, $other->pubkey_t, $this->compressed))) {
71
            throw new \RuntimeException('Unable to serialize public key during equals');
72
        }
73
74
        return hash_equals($pubA, $pubB);
75
    }
76
77
    /**
78
     * @param PublicKeyInterface $other
79
     * @return bool
80
     */
81
    public function equals(PublicKeyInterface $other)
82
    {
83
        /** @var PublicKey $other */
84
        return $this->doEquals($other);
85
    }
86
87
    /**
88
     * @return bool|false
89
     */
90
    public function isCompressed()
91
    {
92
        return $this->compressed;
93
    }
94
95
    /**
96
     * @return resource
97
     */
98
    public function getResource()
99
    {
100
        return $this->pubkey_t;
101
    }
102
103
    /**
104
     * @return resource
105
     * @throws \Exception
106
     */
107
    private function clonePubkey()
108
    {
109
        $context = $this->ecAdapter->getContext();
110
        $serialized = '';
111
        if (1 !== secp256k1_ec_pubkey_serialize($context, $serialized, $this->pubkey_t, $this->compressed)) {
112
            throw new \Exception('Secp256k1: pubkey serialize');
113
        }
114
115
        /** @var resource $clone */
116
        $clone = '';
117
        if (1 !== secp256k1_ec_pubkey_parse($context, $clone, $serialized)) {
118
            throw new \Exception('Secp256k1 pubkey parse');
119
        }
120
121
        return $clone;
122
    }
123
124
    /**
125
     * @param \GMP $tweak
126
     * @return PublicKey
127
     * @throws \Exception
128
     */
129
    public function tweakAdd(\GMP $tweak)
130
    {
131
        $context = $this->ecAdapter->getContext();
132
        $bin = Buffer::int(gmp_strval($tweak, 10), 32)->getBinary();
133
134
        $clone = $this->clonePubkey();
135
        if (1 !== secp256k1_ec_pubkey_tweak_add($context, $clone, $bin)) {
136
            throw new \RuntimeException('Secp256k1: tweak add failed.');
137
        }
138
139
        return new PublicKey($this->ecAdapter, $clone, $this->compressed);
140
    }
141
142
    /**
143
     * @param \GMP $tweak
144
     * @return PublicKey
145
     * @throws \Exception
146
     */
147
    public function tweakMul(\GMP $tweak)
148
    {
149
        $context = $this->ecAdapter->getContext();
150
        $bin = Buffer::int(gmp_strval($tweak, 10), 32)->getBinary();
151
152
        $clone = $this->clonePubkey();
153
        if (1 !== secp256k1_ec_pubkey_tweak_mul($context, $clone, $bin)) {
154
            throw new \RuntimeException('Secp256k1: tweak mul failed.');
155
        }
156
157
        return new PublicKey($this->ecAdapter, $clone, $this->compressed);
158
    }
159
160
    /**
161
     * @return BufferInterface
162
     */
163
    public function getBuffer()
164
    {
165
        return (new PublicKeySerializer($this->ecAdapter))->serialize($this);
166
    }
167
}
168