Completed
Push — master ( 4e3493...96184d )
by thomas
13s
created

V1Hasher::calculate()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 25
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 19
nc 1
nop 3
dl 0
loc 25
ccs 18
cts 18
cp 1
crap 1
rs 8.8571
c 1
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 54
     */
30
    public function __construct(TransactionInterface $transaction, $amount)
31 54
    {
32 54
        $this->transaction = $transaction;
33 54
        $this->amount = $amount;
34
    }
35
36
    /**
37
     * @param int $sighashType
38
     * @return Buffer|BufferInterface
39 54
     */
40
    public function hashPrevOuts($sighashType)
41 54
    {
42 54
        if (!($sighashType & SigHashInterface::ANYONECANPAY)) {
43 54
            $binary = '';
44 54
            foreach ($this->transaction->getInputs() as $input) {
45 10
                $binary .= $input->getOutPoint()->getBinary();
46 54
            }
47
            return Hash::sha256d(new Buffer($binary));
48
        }
49
50
        return new Buffer('', 32);
51
    }
52
53
    /**
54
     * @param int $sighashType
55
     * @return Buffer|BufferInterface
56 54
     */
57
    public function hashSequences($sighashType)
58 54
    {
59 54
        if (!($sighashType & SigHashInterface::ANYONECANPAY) && ($sighashType & 0x1f) != SigHashInterface::SINGLE && ($sighashType & 0x1f) != SigHashInterface::NONE) {
60 54
            $binary = '';
61 54
            foreach ($this->transaction->getInputs() as $input) {
62 10
                $binary .= Buffer::int($input->getSequence())->flip()->getBinary();
63 54
            }
64
            return Hash::sha256d(new Buffer($binary));
65
        }
66
67
        return new Buffer('', 32);
68
    }
69
70
    /**
71
     * @param int $sighashType
72
     * @param int $inputToSign
73
     * @return Buffer|BufferInterface
74 54
     */
75
    public function hashOutputs($sighashType, $inputToSign)
76 54
    {
77 54
        if (($sighashType & 0x1f) !== SigHashInterface::SINGLE && ($sighashType & 0x1f) != SigHashInterface::NONE) {
78 54
            $binary = '';
79 54
            foreach ($this->transaction->getOutputs() as $output) {
80 10
                $binary .= $output->getBinary();
81 54
            }
82
            return Hash::sha256d(new Buffer($binary));
83
        } elseif (($sighashType & 0x1f) == SigHashInterface::SINGLE && $inputToSign < count($this->transaction->getOutputs())) {
84
            return Hash::sha256d($this->transaction->getOutput($inputToSign)->getBuffer());
85
        }
86
87
        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 54
    public function calculate(ScriptInterface $txOutScript, $inputToSign, $sighashType = SigHashInterface::ALL)
102
    {
103 54
        $sighashType = (int) $sighashType;
104
105 54
        $hashPrevOuts = $this->hashPrevOuts($sighashType);
106 54
        $hashSequence = $this->hashSequences($sighashType);
107 54
        $hashOutputs = $this->hashOutputs($sighashType, $inputToSign);
108
        $input = $this->transaction->getInput($inputToSign);
109 54
110
        $scriptBuf = $txOutScript->getBuffer();
111 54
        $preimage = new Buffer(
112 54
            pack("V", $this->transaction->getVersion()) .
113 54
            $hashPrevOuts->getBinary() .
114 54
            $hashSequence->getBinary() .
115 54
            $input->getOutPoint()->getBinary() .
116 54
            Buffertools::numToVarInt($scriptBuf->getSize())->getBinary() . $scriptBuf->getBinary() .
117 54
            Buffer::int($this->amount, 8)->flip()->getBinary() .
118 54
            pack("V", $input->getSequence()) .
119 54
            $hashOutputs->getBinary() .
120 54
            pack("V", $this->transaction->getLockTime()) .
121 54
            pack("V", $sighashType)
122 10
        );
123
124
        return Hash::sha256d($preimage);
125
    }
126
}
127