Completed
Pull Request — master (#754)
by thomas
39:11
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\Exceptions\ParserOutOfRange;
16
use BitWasp\Buffertools\Parser;
17
18
class DerSignatureSerializer implements DerSignatureSerializerInterface
19
{
20
    /**
21
     * @var EcAdapter
22
     */
23
    private $ecAdapter;
24
25
    /**
26
     * @var \BitWasp\Buffertools\Types\VarString
27
     */
28
    private $varstring;
29 2453
30
    /**
31 2453
     * @param EcAdapter $adapter
32 2453
     */
33
    public function __construct(EcAdapter $adapter)
34
    {
35
        $this->ecAdapter = $adapter;
36
        $this->varstring = Types::varstring();
37 244
    }
38
39 244
    /**
40
     * @return EcAdapterInterface
41
     */
42
    public function getEcAdapter(): EcAdapterInterface
43
    {
44
        return $this->ecAdapter;
45 212
    }
46
47 212
    /**
48 212
     * @param SignatureInterface $signature
49 212
     * @return BufferInterface
50 212
     * @throws \Exception
51 212
     */
52 212
    public function serialize(SignatureInterface $signature): BufferInterface
53
    {
54
        $math = $this->ecAdapter->getMath();
55
56
        // Ensure that the R and S hex's are of even length
57
        $rBin = $math->intToString($signature->getR());
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

57
        $rBin = $math->intToString($signature->/** @scrutinizer ignore-call */ getR());
Loading history...
58 219
        $sBin = $math->intToString($signature->getS());
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

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