Completed
Pull Request — master (#359)
by Ruben de
14:27
created

TransactionSignature   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 128
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 7

Test Coverage

Coverage 94.12%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 128
ccs 48
cts 51
cp 0.9412
rs 10
wmc 19
lcom 2
cbo 7

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A getSignature() 0 4 1
A getHashType() 0 4 1
A equals() 0 5 2
C isDERSignature() 0 55 13
A getBuffer() 0 8 1
1
<?php
2
3
namespace BitWasp\Bitcoin\Signature;
4
5
use BitWasp\Bitcoin\Crypto\EcAdapter\Adapter\EcAdapterInterface;
6
use BitWasp\Bitcoin\Crypto\EcAdapter\EcSerializer;
7
use BitWasp\Bitcoin\Crypto\EcAdapter\Serializer\Signature\DerSignatureSerializerInterface;
8
use BitWasp\Bitcoin\Crypto\EcAdapter\Signature\SignatureInterface;
9
use BitWasp\Bitcoin\Exceptions\SignatureNotCanonical;
10
use BitWasp\Bitcoin\Serializable;
11
use BitWasp\Bitcoin\Serializer\Signature\TransactionSignatureSerializer;
12
use BitWasp\Buffertools\BufferInterface;
13
14
class TransactionSignature extends Serializable implements TransactionSignatureInterface
15
{
16
    /**
17
     * @var EcAdapterInterface
18
     */
19
    private $ecAdapter;
20
21
    /**
22
     * @var SignatureInterface
23
     */
24
    private $signature;
25
26
    /**
27
     * @var int|string
28
     */
29
    private $hashType;
30
31
    /**
32
     * @param EcAdapterInterface $ecAdapter
33
     * @param SignatureInterface $signature
34
     * @param $hashType
35
     */
36 114
    public function __construct(EcAdapterInterface $ecAdapter, SignatureInterface $signature, $hashType)
37
    {
38 114
        $this->ecAdapter = $ecAdapter;
39 114
        $this->signature = $signature;
40 114
        $this->hashType = $hashType;
41 114
    }
42
43
    /**
44
     * @return SignatureInterface
45
     */
46 110
    public function getSignature()
47
    {
48 110
        return $this->signature;
49
    }
50
51
    /**
52
     * @return int|string
53
     */
54 110
    public function getHashType()
55
    {
56 110
        return $this->hashType;
57
    }
58
59
    /**
60
     * @param TransactionSignatureInterface $other
61
     * @return bool
62
     */
63
    public function equals(TransactionSignatureInterface $other)
64
    {
65
        return $this->signature->equals($other->getSignature())
66
            && $this->hashType === $other->getHashType();
67
    }
68
69
    /**
70
     * @param BufferInterface $sig
71
     * @return bool
72
     * @throws SignatureNotCanonical
73
     */
74
    public static function isDERSignature(BufferInterface $sig)
75
    {
76 112
        $checkVal = function ($fieldName, $start, $length, $binaryString) {
77 86
            if ($length === 0) {
78 9
                throw new SignatureNotCanonical('Signature ' . $fieldName . ' length is zero');
79
            }
80 83
            $typePrefix = ord(substr($binaryString, $start - 2, 1));
81 83
            if ($typePrefix !== 0x02) {
82 9
                throw new SignatureNotCanonical('Signature ' . $fieldName . ' value type mismatch');
83
            }
84 80
            $val = substr($binaryString, $start, $length);
85 80
            $vAnd = $val[0] & chr(0x80);
86 80
            if (ord($vAnd) === 128) {
87 27
                throw new SignatureNotCanonical('Signature ' . $fieldName . ' value is negative');
88
            }
89 65
            if ($length > 1 && $val[0] === "\x00" && !ord(($val[1] & chr(0x80)))) {
90 15
                throw new SignatureNotCanonical('Signature ' . $fieldName . ' value excessively padded');
91
            }
92 112
        };
93
94 112
        $bin = $sig->getBinary();
95 112
        $size = $sig->getSize();
96 112
        if ($size < 9) {
97 13
            throw new SignatureNotCanonical('Signature too short');
98
        }
99
100 102
        if ($size > 73) {
101 6
            throw new SignatureNotCanonical('Signature too long');
102
        }
103
104 99
        if (ord($bin[0]) !== 0x30) {
105 6
            throw new SignatureNotCanonical('Signature has wrong type');
106
        }
107
108 96
        if (ord($bin[1]) !== $size - 3) {
109 7
            throw new SignatureNotCanonical('Signature has wrong length marker');
110
        }
111
112 92
        $lenR = ord($bin[3]);
113 92
        $startR = 4;
114 92
        if (5 + $lenR >= $size) {
115 6
            throw new SignatureNotCanonical('Signature S length misplaced');
116
        }
117
118 89
        $lenS = ord($bin[5 + $lenR]);
119 89
        $startS = 4 + $lenR + 2;
120 89
        if (($lenR + $lenS + 7) !== $size) {
121 6
            throw new SignatureNotCanonical('Signature R+S length mismatch');
122
        }
123
124 86
        $checkVal('R', $startR, $lenR, $bin);
125 56
        $checkVal('S', $startS, $lenS, $bin);
126
127 41
        return true;
128
    }
129
130
    /**
131
     * @return BufferInterface
132
     */
133 48
    public function getBuffer()
134
    {
135 48
        $txSigSerializer = new TransactionSignatureSerializer(
136 48
            EcSerializer::getSerializer(DerSignatureSerializerInterface::class, true, $this->ecAdapter)
137 16
        );
138
139 48
        return $txSigSerializer->serialize($this);
140
    }
141
}
142