Completed
Push — 0.0.34 ( 61212b...2e9020 )
by thomas
20:55
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 315
    public function getMath()
56
    {
57 315
        return $this->math;
58
    }
59
60
    /**
61
     * @return GeneratorPoint
62
     */
63 36
    public function getGenerator()
64
    {
65 36
        return $this->generator;
66
    }
67
68
    /**
69
     * @param BufferInterface $privateKey
70
     * @return bool
71
     */
72 61
    public function validatePrivateKey(BufferInterface $privateKey)
73
    {
74 61
        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 59
    public function getPrivateKey(\GMP $int, $compressed = false)
99
    {
100 59
        return new PrivateKey($this, $int, $compressed);
101
    }
102
103
    /**
104
     * @return resource
105
     */
106 234
    public function getContext()
107
    {
108 234
        return $this->context;
109
    }
110
111
    /**
112
     * @param BufferInterface $msg32
113
     * @param PrivateKey $privateKey
114
     * @return Signature
115
     */
116 29
    private function doSign(BufferInterface $msg32, PrivateKey $privateKey)
117
    {
118
        /** @var resource $sig_t */
119 29
        $sig_t = '';
120 29
        if (1 !== secp256k1_ecdsa_sign($this->context, $sig_t, $msg32->getBinary(), $privateKey->getBinary())) {
121
            throw new \RuntimeException('Secp256k1: failed to sign');
122
        }
123
124 29
        $derSig = '';
125 29
        secp256k1_ecdsa_signature_serialize_der($this->context, $derSig, $sig_t);
126
127 29
        $rL = ord($derSig[3]);
128 29
        $r = (new Buffer(substr($derSig, 4, $rL), $rL, $this->math))->getGmp();
129
130 29
        $sL = ord($derSig[4+$rL + 1]);
131 29
        $s = (new Buffer(substr($derSig, 4 + $rL + 2, $sL), $sL, $this->math))->getGmp();
132
133 29
        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 29
    public function sign(BufferInterface $msg32, PrivateKeyInterface $privateKey, RbgInterface $rbg = null)
143
    {
144
        /** @var PrivateKey $privateKey */
145 29
        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 90
    private function doVerify(BufferInterface $msg32, PublicKey $publicKey, Signature $signature)
155
    {
156 90
        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 90
    public function verify(BufferInterface $msg32, PublicKeyInterface $publicKey, SignatureInterface $signature)
166
    {
167
        /** @var PublicKey $publicKey */
168
        /** @var Signature $signature */
169 90
        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