Completed
Push — master ( e12674...2b8220 )
by thomas
28:40
created

EcAdapter   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 221
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 59.41%

Importance

Changes 0
Metric Value
dl 0
loc 221
ccs 60
cts 101
cp 0.5941
rs 10
c 0
b 0
f 0
wmc 23
lcom 1
cbo 8

15 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 3
A getMath() 0 4 1
A getGenerator() 0 4 1
A validatePrivateKey() 0 4 1
A getPrivateKey() 0 4 1
A getContext() 0 4 1
A sign() 0 5 1
A doVerify() 0 4 1
A verify() 0 6 1
A doRecover() 0 12 2
A recover() 0 5 1
A signCompact() 0 5 1
A doSign() 0 19 2
A validateSignatureElement() 0 10 3
A doSignCompact() 0 22 3
1
<?php
2
3
namespace BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Adapter;
4
5
use BitWasp\Bitcoin\Crypto\EcAdapter\Adapter\EcAdapterInterface;
6
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Key\PrivateKey;
7
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Key\PublicKey;
8
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Signature\CompactSignature;
9
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Signature\Signature;
10
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\PrivateKeyInterface;
11
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\PublicKeyInterface;
12
use BitWasp\Bitcoin\Crypto\EcAdapter\Signature\CompactSignatureInterface;
13
use BitWasp\Bitcoin\Crypto\EcAdapter\Signature\SignatureInterface;
14
use BitWasp\Bitcoin\Crypto\Random\RbgInterface;
15
use BitWasp\Bitcoin\Math\Math;
16
use BitWasp\Buffertools\Buffer;
17
use BitWasp\Buffertools\BufferInterface;
18
use Mdanter\Ecc\Primitives\GeneratorPoint;
19
20
class EcAdapter implements EcAdapterInterface
21
{
22
    /**
23
     * @var Math
24
     */
25
    private $math;
26
27
    /**
28
     * @var GeneratorPoint
29
     */
30
    private $generator;
31
32
    /**
33
     * @var resource
34
     */
35
    private $context;
36
37
    /**
38
     * @param Math $math
39
     * @param GeneratorPoint $generator
40
     * @param resource $secp256k1_context_t
41
     */
42 5
    public function __construct(Math $math, GeneratorPoint $generator, $secp256k1_context_t)
43
    {
44 5
        if (!is_resource($secp256k1_context_t) || !get_resource_type($secp256k1_context_t) === SECP256K1_TYPE_CONTEXT) {
45
            throw new \InvalidArgumentException('Secp256k1: Must pass a secp256k1_context_t resource');
46
        }
47 5
        $this->math = $math;
48 5
        $this->generator = $generator;
49 5
        $this->context = $secp256k1_context_t;
50 5
    }
51
52
    /**
53
     * @return Math
54
     */
55 347
    public function getMath()
56
    {
57 347
        return $this->math;
58
    }
59
60
    /**
61
     * @return GeneratorPoint
62
     */
63 68
    public function getGenerator()
64
    {
65 68
        return $this->generator;
66
    }
67
68
    /**
69
     * @param BufferInterface $privateKey
70
     * @return bool
71
     */
72 63
    public function validatePrivateKey(BufferInterface $privateKey)
73
    {
74 63
        return (bool) secp256k1_ec_seckey_verify($this->context, $privateKey->getBinary());
75
    }
76
77
    /**
78
     * @param \GMP $element
79
     * @param bool $half
80
     * @return bool
81
     */
82 3
    public function validateSignatureElement(\GMP $element, $half = false)
83
    {
84 3
        $math = $this->getMath();
85 3
        $against = $this->getGenerator()->getOrder();
86 3
        if ($half) {
87 3
            $against = $math->rightShift($against, 1);
88
        }
89
90 3
        return $math->cmp($element, $against) < 0 && $math->cmp($element, gmp_init(0)) !== 0;
91
    }
92
93
    /**
94
     * @param \GMP $int
95
     * @param bool|false $compressed
96
     * @return PrivateKey
97
     */
98 61
    public function getPrivateKey(\GMP $int, $compressed = false)
99
    {
100 61
        return new PrivateKey($this, $int, $compressed);
101
    }
102
103
    /**
104
     * @return resource
105
     */
106 267
    public function getContext()
107
    {
108 267
        return $this->context;
109
    }
110
111
    /**
112
     * @param BufferInterface $msg32
113
     * @param PrivateKey $privateKey
114
     * @return Signature
115
     */
116 61
    private function doSign(BufferInterface $msg32, PrivateKey $privateKey)
117
    {
118
        /** @var resource $sig_t */
119 61
        $sig_t = '';
120 61
        if (1 !== secp256k1_ecdsa_sign($this->context, $sig_t, $msg32->getBinary(), $privateKey->getBinary())) {
121
            throw new \RuntimeException('Secp256k1: failed to sign');
122
        }
123
124 61
        $derSig = '';
125 61
        secp256k1_ecdsa_signature_serialize_der($this->context, $derSig, $sig_t);
126
127 61
        $rL = ord($derSig[3]);
128 61
        $r = (new Buffer(substr($derSig, 4, $rL), $rL, $this->math))->getGmp();
129
130 61
        $sL = ord($derSig[4+$rL + 1]);
131 61
        $s = (new Buffer(substr($derSig, 4 + $rL + 2, $sL), $sL, $this->math))->getGmp();
132
133 61
        return new Signature($this, $r, $s, $sig_t);
134
    }
135
136
    /**
137
     * @param BufferInterface $msg32
138
     * @param PrivateKeyInterface $privateKey
139
     * @param RbgInterface|null $rbg
140
     * @return Signature
141
     */
142 61
    public function sign(BufferInterface $msg32, PrivateKeyInterface $privateKey, RbgInterface $rbg = null)
143
    {
144
        /** @var PrivateKey $privateKey */
145 61
        return $this->doSign($msg32, $privateKey);
146
    }
147
148
    /**
149
     * @param BufferInterface $msg32
150
     * @param PublicKey $publicKey
151
     * @param Signature $signature
152
     * @return bool
153
     */
154 121
    private function doVerify(BufferInterface $msg32, PublicKey $publicKey, Signature $signature)
155
    {
156 121
        return (bool) secp256k1_ecdsa_verify($this->context, $signature->getResource(), $msg32->getBinary(), $publicKey->getResource());
157
    }
158
159
    /**
160
     * @param BufferInterface $msg32
161
     * @param PublicKeyInterface $publicKey
162
     * @param SignatureInterface $signature
163
     * @return bool
164
     */
165 121
    public function verify(BufferInterface $msg32, PublicKeyInterface $publicKey, SignatureInterface $signature)
166
    {
167
        /** @var PublicKey $publicKey */
168
        /** @var Signature $signature */
169 121
        return $this->doVerify($msg32, $publicKey, $signature);
0 ignored issues
show
Compatibility introduced by
$publicKey of type object<BitWasp\Bitcoin\C...Key\PublicKeyInterface> is not a sub-type of object<BitWasp\Bitcoin\C...ecp256k1\Key\PublicKey>. It seems like you assume a concrete implementation of the interface BitWasp\Bitcoin\Crypto\E...\Key\PublicKeyInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
170
    }
171
172
    /**
173
     * @param BufferInterface $msg32
174
     * @param CompactSignature $compactSig
175
     * @return PublicKey
176
     */
177 6
    private function doRecover(BufferInterface $msg32, CompactSignature $compactSig)
178
    {
179 6
        $publicKey = '';
180
        /** @var resource $publicKey */
181 6
        $context = $this->context;
182 6
        $sig = $compactSig->getResource();
183 6
        if (1 !== secp256k1_ecdsa_recover($context, $publicKey, $sig, $msg32->getBinary())) {
184
            throw new \RuntimeException('Unable to recover Public Key');
185
        }
186
187 6
        return new PublicKey($this, $publicKey, $compactSig->isCompressed());
188
    }
189
190
    /**
191
     * @param BufferInterface $msg32
192
     * @param CompactSignatureInterface $compactSig
193
     * @return PublicKey
194
     */
195 6
    public function recover(BufferInterface $msg32, CompactSignatureInterface $compactSig)
196
    {
197
        /** @var CompactSignature $compactSig */
198 6
        return $this->doRecover($msg32, $compactSig);
199
    }
200
201
    /**
202
     * @param BufferInterface $msg32
203
     * @param PrivateKey $privateKey
204
     * @return CompactSignature
205
     */
206 5
    private function doSignCompact(BufferInterface $msg32, PrivateKey $privateKey)
207
    {
208 5
        $sig_t = '';
209
        /** @var resource $sig_t */
210 5
        if (1 !== secp256k1_ecdsa_sign_recoverable($this->context, $sig_t, $msg32->getBinary(), $privateKey->getBinary())) {
211
            throw new \RuntimeException('Secp256k1: failed to sign');
212
        }
213
214 5
        $recid = '';
215 5
        $ser = '';
216 5
        if (!secp256k1_ecdsa_recoverable_signature_serialize_compact($this->context, $sig_t, $ser, $recid)) {
217
            throw new \RuntimeException('Failed to obtain recid');
218
        }
219
220 5
        unset($ser);
221 5
        return new CompactSignature(
222 5
            $this,
223 5
            $sig_t,
224 5
            $recid,
225 5
            $privateKey->isCompressed()
226
        );
227
    }
228
229
    /**
230
     * @param BufferInterface $msg32
231
     * @param PrivateKeyInterface $privateKey
232
     * @param RbgInterface|null $rbg
233
     * @return CompactSignatureInterface
234
     */
235 5
    public function signCompact(BufferInterface $msg32, PrivateKeyInterface $privateKey, RbgInterface $rbg = null)
236
    {
237
        /** @var PrivateKey $privateKey */
238 5
        return $this->doSignCompact($msg32, $privateKey);
239
    }
240
}
241