Completed
Push — master ( 46e6d3...cfc147 )
by thomas
208:06 queued 195:14
created

V1Hasher::hashOutputs()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 9
nc 4
nop 2
dl 0
loc 14
ccs 10
cts 10
cp 1
crap 6
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
namespace BitWasp\Bitcoin\Transaction\SignatureHash;
4
5
use BitWasp\Bitcoin\Crypto\Hash;
6
use BitWasp\Bitcoin\Script\ScriptFactory;
7
use BitWasp\Bitcoin\Transaction\TransactionInterface;
8
use BitWasp\Buffertools\Buffer;
9
use BitWasp\Buffertools\BufferInterface;
10
use BitWasp\Bitcoin\Script\ScriptInterface;
11
use BitWasp\Buffertools\Buffertools;
12
13
class V1Hasher
14
{
15
    /**
16
     * @var TransactionInterface
17
     */
18
    private $transaction;
19
20
    /**
21
     * @var int|string
22
     */
23
    private $amount;
24
25
    /**
26
     * V1Hasher constructor.
27
     * @param TransactionInterface $transaction
28
     * @param int|string $amount
29
     */
30 126
    public function __construct(TransactionInterface $transaction, $amount)
31
    {
32 126
        $this->transaction = $transaction;
33 126
        $this->amount = $amount;
34 126
    }
35
36
    /**
37
     * @param int $sighashType
38
     * @return Buffer|BufferInterface
39
     */
40 126
    public function hashPrevOuts($sighashType)
41
    {
42 126
        if (!($sighashType & SigHashInterface::ANYONECANPAY)) {
43 108
            $binary = '';
44 108
            foreach ($this->transaction->getInputs() as $input) {
45 108
                $binary .= $input->getOutPoint()->getBinary();
46 44
            }
47 108
            return Hash::sha256d(new Buffer($binary));
48
        }
49
50 18
        return new Buffer('', 32);
51
    }
52
53
    /**
54
     * @param int $sighashType
55
     * @return Buffer|BufferInterface
56
     */
57 126
    public function hashSequences($sighashType)
58
    {
59 126
        if (!($sighashType & SigHashInterface::ANYONECANPAY) && ($sighashType & 0x1f) != SigHashInterface::SINGLE && ($sighashType & 0x1f) != SigHashInterface::NONE) {
60 96
            $binary = '';
61 96
            foreach ($this->transaction->getInputs() as $input) {
62 96
                $binary .= Buffer::int($input->getSequence())->flip()->getBinary();
63 40
            }
64 96
            return Hash::sha256d(new Buffer($binary));
65
        }
66
67 30
        return new Buffer('', 32);
68
    }
69
70
    /**
71
     * @param int $sighashType
72
     * @param int $inputToSign
73
     * @return Buffer|BufferInterface
74
     */
75 126
    public function hashOutputs($sighashType, $inputToSign)
76
    {
77 126
        if (($sighashType & 0x1f) !== SigHashInterface::SINGLE && ($sighashType & 0x1f) != SigHashInterface::NONE) {
78 102
            $binary = '';
79 102
            foreach ($this->transaction->getOutputs() as $output) {
80 102
                $binary .= $output->getBinary();
81 42
            }
82 102
            return Hash::sha256d(new Buffer($binary));
83 24
        } elseif (($sighashType & 0x1f) == SigHashInterface::SINGLE && $inputToSign < count($this->transaction->getOutputs())) {
84 12
            return Hash::sha256d($this->transaction->getOutput($inputToSign)->getBuffer());
85
        }
86
87 12
        return new Buffer('', 32);
88
    }
89
90
    /**
91
     * Calculate the hash of the current transaction, when you are looking to
92
     * spend $txOut, and are signing $inputToSign. The SigHashType defaults to
93
     * SIGHASH_ALL
94
     *
95
     * @param ScriptInterface $txOutScript
96
     * @param int $inputToSign
97
     * @param int $sighashType
98
     * @return BufferInterface
99
     * @throws \Exception
100
     */
101 126
    public function calculate(ScriptInterface $txOutScript, $inputToSign, $sighashType = SigHashInterface::ALL)
102
    {
103 126
        $sighashType = (int) $sighashType;
104
105 126
        $hashPrevOuts = $this->hashPrevOuts($sighashType);
106 126
        $hashSequence = $this->hashSequences($sighashType);
107 126
        $hashOutputs = $this->hashOutputs($sighashType, $inputToSign);
108 126
        $input = $this->transaction->getInput($inputToSign);
109
110 126
        $scriptBuf = $txOutScript->getBuffer();
111 126
        $preimage = new Buffer(
112 126
            pack("V", $this->transaction->getVersion()) .
113 126
            $hashPrevOuts->getBinary() .
114 126
            $hashSequence->getBinary() .
115 126
            $input->getOutPoint()->getBinary() .
116 126
            Buffertools::numToVarInt($scriptBuf->getSize())->getBinary() . $scriptBuf->getBinary() .
117 126
            Buffer::int($this->amount, 8)->flip()->getBinary() .
118 126
            pack("V", $input->getSequence()) .
119 126
            $hashOutputs->getBinary() .
120 126
            pack("V", $this->transaction->getLockTime()) .
121 126
            pack("V", $sighashType)
122 50
        );
123
124 126
        return Hash::sha256d($preimage);
125
    }
126
}
127