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

EcAdapter   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 221
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
dl 0
loc 221
ccs 0
cts 101
cp 0
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 doSignCompact() 0 22 3
A signCompact() 0 5 1
A validateSignatureElement() 0 10 3
A doSign() 0 19 2
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
    public function __construct(Math $math, GeneratorPoint $generator, $secp256k1_context_t)
43
    {
44
        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
        $this->math = $math;
48
        $this->generator = $generator;
49
        $this->context = $secp256k1_context_t;
50
    }
51
52
    /**
53
     * @return Math
54
     */
55
    public function getMath()
56
    {
57
        return $this->math;
58
    }
59
60
    /**
61
     * @return GeneratorPoint
62
     */
63
    public function getGenerator()
64
    {
65
        return $this->generator;
66
    }
67
68
    /**
69
     * @param BufferInterface $privateKey
70
     * @return bool
71
     */
72
    public function validatePrivateKey(BufferInterface $privateKey)
73
    {
74
        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
    public function validateSignatureElement(\GMP $element, $half = false)
83
    {
84
        $math = $this->getMath();
85
        $against = $this->getGenerator()->getOrder();
86
        if ($half) {
87
            $against = $math->rightShift($against, 1);
88
        }
89
90
        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
    public function getPrivateKey(\GMP $int, $compressed = false)
99
    {
100
        return new PrivateKey($this, $int, $compressed);
101
    }
102
103
    /**
104
     * @return resource
105
     */
106
    public function getContext()
107
    {
108
        return $this->context;
109
    }
110
111
    /**
112
     * @param BufferInterface $msg32
113
     * @param PrivateKey $privateKey
114
     * @return Signature
115
     */
116
    private function doSign(BufferInterface $msg32, PrivateKey $privateKey)
117
    {
118
        /** @var resource $sig_t */
119
        $sig_t = '';
120
        if (1 !== secp256k1_ecdsa_sign($this->context, $sig_t, $msg32->getBinary(), $privateKey->getBinary())) {
121
            throw new \RuntimeException('Secp256k1: failed to sign');
122
        }
123
124
        $derSig = '';
125
        secp256k1_ecdsa_signature_serialize_der($this->context, $derSig, $sig_t);
126
127
        $rL = ord($derSig[3]);
128
        $r = (new Buffer(substr($derSig, 4, $rL), $rL, $this->math))->getGmp();
129
130
        $sL = ord($derSig[4+$rL + 1]);
131
        $s = (new Buffer(substr($derSig, 4 + $rL + 2, $sL), $sL, $this->math))->getGmp();
132
133
        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
    public function sign(BufferInterface $msg32, PrivateKeyInterface $privateKey, RbgInterface $rbg = null)
143
    {
144
        /** @var PrivateKey $privateKey */
145
        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
    private function doVerify(BufferInterface $msg32, PublicKey $publicKey, Signature $signature)
155
    {
156
        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
    public function verify(BufferInterface $msg32, PublicKeyInterface $publicKey, SignatureInterface $signature)
166
    {
167
        /** @var PublicKey $publicKey */
168
        /** @var Signature $signature */
169
        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
    private function doRecover(BufferInterface $msg32, CompactSignature $compactSig)
178
    {
179
        $publicKey = '';
180
        /** @var resource $publicKey */
181
        $context = $this->context;
182
        $sig = $compactSig->getResource();
183
        if (1 !== secp256k1_ecdsa_recover($context, $publicKey, $sig, $msg32->getBinary())) {
184
            throw new \RuntimeException('Unable to recover Public Key');
185
        }
186
187
        return new PublicKey($this, $publicKey, $compactSig->isCompressed());
188
    }
189
190
    /**
191
     * @param BufferInterface $msg32
192
     * @param CompactSignatureInterface $compactSig
193
     * @return PublicKey
194
     */
195
    public function recover(BufferInterface $msg32, CompactSignatureInterface $compactSig)
196
    {
197
        /** @var CompactSignature $compactSig */
198
        return $this->doRecover($msg32, $compactSig);
199
    }
200
201
    /**
202
     * @param BufferInterface $msg32
203
     * @param PrivateKey $privateKey
204
     * @return CompactSignature
205
     */
206
    private function doSignCompact(BufferInterface $msg32, PrivateKey $privateKey)
207
    {
208
        $sig_t = '';
209
        /** @var resource $sig_t */
210
        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
        $recid = '';
215
        $ser = '';
216
        if (!secp256k1_ecdsa_recoverable_signature_serialize_compact($this->context, $sig_t, $ser, $recid)) {
217
            throw new \RuntimeException('Failed to obtain recid');
218
        }
219
220
        unset($ser);
221
        return new CompactSignature(
222
            $this,
223
            $sig_t,
224
            $recid,
225
            $privateKey->isCompressed()
226
        );
227
    }
228
229
    /**
230
     * @param BufferInterface $msg32
231
     * @param PrivateKeyInterface $privateKey
232
     * @param RbgInterface|null $rbg
233
     * @return CompactSignatureInterface
234
     */
235
    public function signCompact(BufferInterface $msg32, PrivateKeyInterface $privateKey, RbgInterface $rbg = null)
236
    {
237
        /** @var PrivateKey $privateKey */
238
        return $this->doSignCompact($msg32, $privateKey);
239
    }
240
}
241