Passed
Push — master ( 280df4...3ba82a )
by thomas
51:58 queued 49:57
created

DerSignatureSerializer::getOuterTemplate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 0
dl 0
loc 6
ccs 5
cts 5
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BitWasp\Bitcoin\Crypto\EcAdapter\Impl\PhpEcc\Serializer\Signature;
6
7
use BitWasp\Bitcoin\Crypto\EcAdapter\Adapter\EcAdapterInterface;
8
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\PhpEcc\Adapter\EcAdapter;
9
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\PhpEcc\Signature\Signature;
10
use BitWasp\Bitcoin\Crypto\EcAdapter\Serializer\Signature\DerSignatureSerializerInterface;
11
use BitWasp\Bitcoin\Crypto\EcAdapter\Signature\SignatureInterface;
12
use BitWasp\Bitcoin\Serializer\Types;
13
use BitWasp\Buffertools\Buffer;
14
use BitWasp\Buffertools\BufferInterface;
15
use BitWasp\Buffertools\Buffertools;
16
use BitWasp\Buffertools\Exceptions\ParserOutOfRange;
17
use BitWasp\Buffertools\Parser;
18
19
class DerSignatureSerializer implements DerSignatureSerializerInterface
20
{
21
    /**
22
     * @var EcAdapter
23
     */
24
    private $ecAdapter;
25
26
    /**
27
     * @var \BitWasp\Buffertools\Types\VarString
28
     */
29
    private $varstring;
30
31
    /**
32
     * @param EcAdapter $adapter
33
     */
34 2454
    public function __construct(EcAdapter $adapter)
35
    {
36 2454
        $this->ecAdapter = $adapter;
37 2454
        $this->varstring = Types::varstring();
38 2454
    }
39
40
    /**
41
     * @return EcAdapterInterface
42
     */
43 244
    public function getEcAdapter(): EcAdapterInterface
44
    {
45 244
        return $this->ecAdapter;
46
    }
47
48
    /**
49
     * @param SignatureInterface $signature
50
     * @return BufferInterface
51
     * @throws \Exception
52
     */
53 69
    public function serialize(SignatureInterface $signature): BufferInterface
54
    {
55
        // Ensure that the R and S hex's are of even length
56 69
        $rBin = gmp_export($signature->getR(), 1, GMP_MSW_FIRST | GMP_BIG_ENDIAN);
0 ignored issues
show
Bug introduced by
The method getR() does not exist on BitWasp\Bitcoin\Crypto\E...ture\SignatureInterface. It seems like you code against a sub-type of BitWasp\Bitcoin\Crypto\E...ture\SignatureInterface such as BitWasp\Bitcoin\Crypto\E...6k1\Signature\Signature or BitWasp\Bitcoin\Crypto\E...Ecc\Signature\Signature or BitWasp\Bitcoin\Crypto\E...nature\CompactSignature or BitWasp\Bitcoin\Crypto\E...nature\CompactSignature. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

56
        $rBin = gmp_export($signature->/** @scrutinizer ignore-call */ getR(), 1, GMP_MSW_FIRST | GMP_BIG_ENDIAN);
Loading history...
57 69
        $sBin = gmp_export($signature->getS(), 1, GMP_MSW_FIRST | GMP_BIG_ENDIAN);
0 ignored issues
show
Bug introduced by
The method getS() does not exist on BitWasp\Bitcoin\Crypto\E...ture\SignatureInterface. It seems like you code against a sub-type of BitWasp\Bitcoin\Crypto\E...ture\SignatureInterface such as BitWasp\Bitcoin\Crypto\E...6k1\Signature\Signature or BitWasp\Bitcoin\Crypto\E...Ecc\Signature\Signature or BitWasp\Bitcoin\Crypto\E...nature\CompactSignature or BitWasp\Bitcoin\Crypto\E...nature\CompactSignature. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

57
        $sBin = gmp_export($signature->/** @scrutinizer ignore-call */ getS(), 1, GMP_MSW_FIRST | GMP_BIG_ENDIAN);
Loading history...
58
59
        // Pad R and S if their highest bit is flipped, ie,
60
        // they are negative.
61 69
        if ((ord($rBin[0]) & 0x80) === 0x80) {
62 39
            $rBin = "\x00$rBin";
63
        }
64
65 69
        if ((ord($sBin[0]) & 0x80) === 0x80) {
66 2
            $sBin = "\x00$sBin";
67
        }
68
69 69
        $inner = sprintf(
70 69
            "\x02%s%s\x02%s%s",
71 69
            Buffertools::numToVarIntBin(strlen($rBin)),
72 69
            $rBin,
73 69
            Buffertools::numToVarIntBin(strlen($sBin)),
74 69
            $sBin
75
        );
76
77 69
        return new Buffer(sprintf("\x30%s%s", Buffertools::numToVarIntBin(strlen($inner)), $inner));
78
    }
79
80
    /**
81
     * @param Parser $parser
82
     * @return SignatureInterface
83
     * @throws ParserOutOfRange
84
     */
85 209
    public function fromParser(Parser $parser): SignatureInterface
86
    {
87 209
        $prefix = $parser->readBytes(1);
88 204
        if ($prefix->getBinary() != "\x30") {
89 4
            throw new \RuntimeException("invalid signature");
90
        }
91 200
        $inner = $this->varstring->read($parser);
92
93
        try {
94 200
            $pinner = new Parser($inner);
95
96 200
            $rPref = $pinner->readBytes(1);
97 200
            if ($rPref->getBinary() != "\x02") {
98 2
                throw new \RuntimeException("invalid signature");
99
            }
100 198
            $r = $this->varstring->read($pinner);
101
102 198
            $sPref = $pinner->readBytes(1);
103 196
            if ($sPref->getBinary() != "\x02") {
104 2
                throw new \RuntimeException("invalid signature");
105
            }
106 194
            $s = $this->varstring->read($pinner);
107 6
        } catch (ParserOutOfRange $e) {
108 2
            throw new ParserOutOfRange('Failed to extract full signature from parser');
109
        }
110
111 194
        return new Signature($this->ecAdapter, $r->getGmp(), $s->getGmp());
112
    }
113
114
    /**
115
     * @param BufferInterface $derSignature
116
     * @return SignatureInterface
117
     * @throws ParserOutOfRange
118
     */
119 209
    public function parse(BufferInterface $derSignature): SignatureInterface
120
    {
121 209
        return $this->fromParser(new Parser($derSignature));
122
    }
123
}
124