Completed
Push — master ( 508371...265855 )
by thomas
68:00 queued 64:13
created

DerSignatureSerializer::serialize()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 30
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 17
c 1
b 0
f 0
nc 4
nop 1
dl 0
loc 30
ccs 21
cts 21
cp 1
crap 3
rs 8.8571
1
<?php
2
3
namespace BitWasp\Bitcoin\Crypto\EcAdapter\Impl\PhpEcc\Serializer\Signature;
4
5
use BitWasp\Bitcoin\Crypto\EcAdapter\Adapter\EcAdapterInterface;
6
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\PhpEcc\Adapter\EcAdapter;
7
use BitWasp\Bitcoin\Crypto\EcAdapter\Serializer\Signature\DerSignatureSerializerInterface;
8
use BitWasp\Buffertools\BufferInterface;
9
use BitWasp\Buffertools\Exceptions\ParserOutOfRange;
10
use BitWasp\Buffertools\Parser;
11
use BitWasp\Buffertools\Buffer;
12
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\PhpEcc\Signature\Signature;
13
use BitWasp\Bitcoin\Crypto\EcAdapter\Signature\SignatureInterface;
14
use BitWasp\Buffertools\Template;
15
use BitWasp\Buffertools\TemplateFactory;
16
17
class DerSignatureSerializer implements DerSignatureSerializerInterface
18
{
19
    /**
20
     * @var EcAdapter
21
     */
22
    private $ecAdapter;
23
24
    /**
25
     * @param EcAdapter $adapter
26
     */
27 201
    public function __construct(EcAdapter $adapter)
28
    {
29 201
        $this->ecAdapter = $adapter;
30 201
    }
31
32
    /**
33
     * @return EcAdapterInterface
34
     */
35 190
    public function getEcAdapter()
36
    {
37 190
        return $this->ecAdapter;
38
    }
39
40
    /**
41
     * @return Template
42
     */
43 169
    private function getInnerTemplate()
44
    {
45 169
        return (new TemplateFactory())
46 169
            ->uint8()
47 169
            ->varstring()
48 169
            ->uint8()
49 169
            ->varstring()
50 169
            ->getTemplate();
51
    }
52
53
    /**
54
     * @return Template
55
     */
56 201
    private function getOuterTemplate()
57
    {
58 201
        return (new TemplateFactory())
59 201
            ->uint8()
60 201
            ->varstring()
61 201
            ->getTemplate();
62
    }
63
64
    /**
65
     * @param SignatureInterface $signature
66
     * @return BufferInterface
67
     */
68 35
    public function serialize(SignatureInterface $signature)
69
    {
70 35
        $math = $this->ecAdapter->getMath();
71
72
        // Ensure that the R and S hex's are of even length
73 35
        $rBin = pack('H*', $math->decHex($math->toString($signature->getR())));
74 35
        $sBin = pack('H*', $math->decHex($math->toString($signature->getS())));
75
76
        // Pad R and S if their highest bit is flipped, ie,
77
        // they are negative.
78 35
        $rt = $rBin[0] & pack('H*', '80');
79 35
        if (ord($rt) === 128) {
80 14
            $rBin = pack('H*', '00') . $rBin;
81 7
        }
82
83 35
        $st = $sBin[0] & pack('H*', '80');
84 35
        if (ord($st) === 128) {
85 7
            $sBin = pack('H*', '00') . $sBin;
86 4
        }
87
88 35
        return $this->getOuterTemplate()->write([
89 35
            0x30,
90 35
            $this->getInnerTemplate()->write([
91 35
                0x02,
92 35
                new Buffer($rBin, null, $math),
93 35
                0x02,
94 35
                new Buffer($sBin, null, $math)
95 18
            ])
96 18
        ]);
97
    }
98
99
    /**
100
     * @param Parser $parser
101
     * @return Signature
102
     * @throws ParserOutOfRange
103
     */
104 194
    public function fromParser(Parser $parser)
105
    {
106
        try {
107 194
            list (, $inner) = $this->getOuterTemplate()->parse($parser);
108 162
            list (, $r, , $s) = $this->getInnerTemplate()->parse(new Parser($inner));
109
            /** @var Buffer $r */
110
            /** @var Buffer $s */
111
112 158
            return new Signature(
113 158
                $this->ecAdapter,
114 158
                $r->getGmp(),
115 156
                $s->getGmp()
116 77
            );
117 44
        } catch (ParserOutOfRange $e) {
118 40
            throw new ParserOutOfRange('Failed to extract full signature from parser');
119
        }
120
    }
121
122
    /**
123
     * @param BufferInterface|$string
124
     * @return Signature
125
     * @throws ParserOutOfRange
126
     */
127 194
    public function parse($string)
128
    {
129 194
        $parser = new Parser($string);
130 194
        $signature = $this->fromParser($parser);
131 154
        return $signature;
132
    }
133
}
134