Completed
Pull Request — master (#229)
by thomas
123:03 queued 47:24
created

EcAdapter   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 221
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 61.54%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 221
wmc 23
lcom 1
cbo 7
ccs 64
cts 104
cp 0.6154
rs 10

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 validateSignatureElement() 0 10 3
A getPrivateKey() 0 4 1
A getContext() 0 4 1
A doSign() 0 19 2
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 doSignCompact() 0 22 3
A signCompact() 0 5 1
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\PublicKey;
7
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Key\PrivateKey;
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\PublicKeyInterface;
11
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\PrivateKeyInterface;
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 Mdanter\Ecc\Primitives\GeneratorPoint;
18
19
class EcAdapter implements EcAdapterInterface
20
{
21
    /**
22
     * @var Math
23
     */
24
    private $math;
25
26
    /**
27
     * @var GeneratorPoint
28
     */
29
    private $generator;
30
31
    /**
32
     * @var resource
33
     */
34
    private $context;
35
36
    /**
37
     * @param Math $math
38
     * @param GeneratorPoint $generator
39
     * @param resource $secp256k1_context_t
40
     */
41 33
    public function __construct(Math $math, GeneratorPoint $generator, $secp256k1_context_t)
42
    {
43 33
        if (!is_resource($secp256k1_context_t) || !get_resource_type($secp256k1_context_t) === SECP256K1_TYPE_CONTEXT) {
44
            throw new \InvalidArgumentException('Secp256k1: Must pass a secp256k1_context_t resource');
45
        }
46 33
        $this->math = $math;
47 33
        $this->generator = $generator;
48 33
        $this->context = $secp256k1_context_t;
49 33
    }
50
51
    /**
52
     * @return Math
53
     */
54 924
    public function getMath()
55
    {
56 924
        return $this->math;
57
    }
58
59
    /**
60
     * @return GeneratorPoint
61
     */
62 69
    public function getGenerator()
63
    {
64 69
        return $this->generator;
65
    }
66
67
    /**
68
     * @param Buffer $privateKey
69
     * @return bool
70
     */
71 234
    public function validatePrivateKey(Buffer $privateKey)
72
    {
73 234
        return (bool) secp256k1_ec_seckey_verify($this->context, $privateKey->getBinary());
74
    }
75
76
    /**
77
     * @param int|string $element
78
     * @param bool $half
79
     * @return bool
80
     */
81
    public function validateSignatureElement($element, $half = false)
82 3
    {
83
        $math = $this->getMath();
84 3
        $against = $this->getGenerator()->getOrder();
85 3
        if ($half) {
86 3
            $against = $math->rightShift($against, 1);
87 3
        }
88 3
89 3
        return $math->cmp($element, $against) < 0 && $math->cmp($element, 0) !== 0;
90 3
    }
91 3
92 3
    /**
93
     * @param int|string $int
94
     * @param bool|false $compressed
95
     * @return PrivateKey
96
     */
97 3
    public function getPrivateKey($int, $compressed = false)
98 3
    {
99 3
        return new PrivateKey($this, $int, $compressed);
100
    }
101
102
    /**
103
     * @return resource
104
     */
105
    public function getContext()
106
    {
107 12
        return $this->context;
108
    }
109 12
110 12
    /**
111 12
     * @param Buffer $msg32
112 12
     * @param PrivateKey $privateKey
113 12
     * @return Signature
114
     */
115 12
    private function doSign(Buffer $msg32, PrivateKey $privateKey)
116
    {
117
        /** @var resource $sig_t */
118
        $sig_t = '';
119
        if (1 !== secp256k1_ecdsa_sign($this->context, $msg32->getBinary(), $privateKey->getBinary(), $sig_t)) {
120
            throw new \RuntimeException('Secp256k1: failed to sign');
121
        }
122
123 228
        $derSig = '';
124
        secp256k1_ecdsa_signature_serialize_der($this->context, $sig_t, $derSig);
125 228
126
        $rL = ord($derSig[3]);
127
        $r = (new Buffer(substr($derSig, 4, $rL), $rL, $this->math))->getInt();
128
129
        $sL = ord($derSig[4+$rL + 1]);
130
        $s = (new Buffer(substr($derSig, 4 + $rL + 2, $sL), $rL, $this->math))->getInt();
131 432
132
        return new Signature($this, $r, $s, $sig_t);
133 432
    }
134
135
    /**
136
     * @param Buffer $msg32
137
     * @param PrivateKeyInterface $privateKey
138
     * @param RbgInterface|null $rbg
139
     * @return Signature
140
     */
141 48
    public function sign(Buffer $msg32, PrivateKeyInterface $privateKey, RbgInterface $rbg = null)
142
    {
143
        /** @var PrivateKey $privateKey */
144 48
        return $this->doSign($msg32, $privateKey);
145 48
    }
146
147
    /**
148
     * @param Buffer $msg32
149 48
     * @param PublicKey $publicKey
150 48
     * @param Signature $signature
151
     * @return bool
152 48
     */
153 48
    private function doVerify(Buffer $msg32, PublicKey $publicKey, Signature $signature)
154
    {
155 48
        return (bool) secp256k1_ecdsa_verify($this->context, $msg32->getBinary(), $signature->getResource(), $publicKey->getResource());
156 48
    }
157
158 48
    /**
159
     * @param Buffer $msg32
160
     * @param PublicKeyInterface $publicKey
161
     * @param SignatureInterface $signature
162
     * @return bool
163
     */
164
    public function verify(Buffer $msg32, PublicKeyInterface $publicKey, SignatureInterface $signature)
165
    {
166
        /** @var PublicKey $publicKey */
167 48
        /** @var Signature $signature */
168
        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...
169
    }
170 48
171
    /**
172
     * @param Buffer $msg32
173
     * @param CompactSignature $compactSig
174
     * @return PublicKey
175
     */
176
    private function doRecover(Buffer $msg32, CompactSignature $compactSig)
177
    {
178
        $publicKey = '';
179 18
        /** @var resource $publicKey */
180
        $context = $this->context;
181 18
        $sig = $compactSig->getResource();
182
        if (1 !== secp256k1_ecdsa_recover($context, $msg32->getBinary(), $sig, $publicKey)) {
183
            throw new \RuntimeException('Unable to recover Public Key');
184
        }
185
186
        return new PublicKey($this, $publicKey, $compactSig->isCompressed());
187
    }
188
189
    /**
190 18
     * @param Buffer $msg32
191
     * @param CompactSignatureInterface $compactSig
192
     * @return PublicKey
193
     */
194 18
    public function recover(Buffer $msg32, CompactSignatureInterface $compactSig)
195
    {
196
        /** @var CompactSignature $compactSig */
197
        return $this->doRecover($msg32, $compactSig);
198
    }
199
200
    /**
201
     * @param Buffer $msg32
202 21
     * @param PrivateKey $privateKey
203
     * @return CompactSignature
204 21
     */
205
    private function doSignCompact(Buffer $msg32, PrivateKey $privateKey)
206 21
    {
207 21
        $sig_t = '';
208 21
        /** @var resource $sig_t */
209
        if (1 !== secp256k1_ecdsa_sign_recoverable($this->context, $msg32->getBinary(), $privateKey->getBinary(), $sig_t)) {
210
            throw new \RuntimeException('Secp256k1: failed to sign');
211
        }
212 21
213
        $recid = '';
214
        $ser = '';
215
        if (!secp256k1_ecdsa_recoverable_signature_serialize_compact($this->context, $sig_t, $ser, $recid)) {
216
            throw new \RuntimeException('Failed to obtain recid');
217
        }
218
219
        unset($ser);
220 21
        return new CompactSignature(
221
            $this,
222
            $sig_t,
223 21
            $recid,
224
            $privateKey->isCompressed()
225
        );
226
    }
227
228
    /**
229
     * @param Buffer $msg32
230
     * @param PrivateKeyInterface $privateKey
231 18
     * @param RbgInterface|null $rbg
232
     * @return CompactSignatureInterface
233 18
     */
234
    public function signCompact(Buffer $msg32, PrivateKeyInterface $privateKey, RbgInterface $rbg = null)
235 18
    {
236
        /** @var PrivateKey $privateKey */
237
        return $this->doSignCompact($msg32, $privateKey);
238
    }
239
}
240