1
// Copyright © 2017-2020 Trust Wallet.
2
//
3
// This file is part of Trust. The full Trust copyright notice, including
4
// terms governing use, modification, and redistribution, is contained in the
5
// file LICENSE at the root of the source code distribution tree.
6

7
#include "Transaction.h"
8

9
#include "../Bitcoin/SigHashType.h"
10
#include "../BinaryCoding.h"
11
#include "../Hash.h"
12
#include  "../HexCoding.h"
13

14
#include <cassert>
15

16
using namespace TW;
17
using namespace TW::Zcash;
18

19 1
const auto sigHashPersonalization = Data({'Z','c','a','s','h','S','i','g','H','a','s','h'});
20 1
const auto prevoutsHashPersonalization = Data({'Z','c','a','s','h','P','r','e','v','o','u','t','H','a','s','h'});
21 1
const auto sequenceHashPersonalization = Data({'Z','c','a','s','h','S','e','q','u','e','n','c','H','a','s','h'});
22 1
const auto outputsHashPersonalization = Data({'Z','c','a','s','h','O','u','t','p','u','t','s','H','a','s','h'});
23 1
const auto joinsplitsHashPersonalization = Data({'Z','c','a','s','h','J','S','p','l','i','t','s','H','a','s','h'});
24 1
const auto shieldedSpendHashPersonalization = Data({'Z','c','a','s','h','S','S','p','e','n','d','s','H','a','s','h'});
25 1
const auto shieldedOutputsHashPersonalization = Data({'Z','c','a','s','h','S','O','u','t','p','u','t','H','a','s','h'});
26

27
/// See https://github.com/zcash/zips/blob/master/zip-0205.rst#sapling-deployment BRANCH_ID section
28
const std::array<byte, 4> Zcash::SaplingBranchID = {0xbb, 0x09, 0xb8, 0x76};
29
/// See https://github.com/zcash/zips/blob/master/zip-0206.rst#blossom-deployment BRANCH_ID section
30
const std::array<byte, 4> Zcash::BlossomBranchID = {0x60, 0x0e, 0xb4, 0x2b};
31

32 1
Data Transaction::getPreImage(const Bitcoin::Script& scriptCode, size_t index, enum TWBitcoinSigHashType hashType,
33
                              uint64_t amount) const {
34 1
    assert(index < inputs.size());
35

36 1
    auto data = Data{};
37

38
    // header
39 1
    encode32LE(version, data);
40

41
    // nVersionGroupId
42 1
    encode32LE(versionGroupId, data);
43

44
    // Input prevouts (none/all, depending on flags)
45 1
    if ((hashType & TWBitcoinSigHashTypeAnyoneCanPay) == 0) {
46 1
        auto hashPrevouts = getPrevoutHash();
47 1
        std::copy(std::begin(hashPrevouts), std::end(hashPrevouts), std::back_inserter(data));
48 1
    } else {
49 0
        std::fill_n(back_inserter(data), 32, 0);
50
    }
51

52
    // Input nSequence (none/all, depending on flags)
53 1
    if ((hashType & TWBitcoinSigHashTypeAnyoneCanPay) == 0 &&
54 1
        !Bitcoin::hashTypeIsSingle(hashType) && !Bitcoin::hashTypeIsNone(hashType)) {
55 1
        auto hashSequence = getSequenceHash();
56 1
        std::copy(std::begin(hashSequence), std::end(hashSequence), std::back_inserter(data));
57 1
    } else {
58 0
        std::fill_n(back_inserter(data), 32, 0);
59
    }
60

61
    // Outputs (none/one/all, depending on flags)
62 1
    if (!Bitcoin::hashTypeIsSingle(hashType) && !Bitcoin::hashTypeIsNone(hashType)) {
63 1
        auto hashOutputs = getOutputsHash();
64 1
        copy(begin(hashOutputs), end(hashOutputs), back_inserter(data));
65 1
    } else if (Bitcoin::hashTypeIsSingle(hashType) && index < outputs.size()) {
66 0
        auto outputData = Data{};
67 0
        outputs[index].encode(outputData);
68
        auto hashOutputs =
69 0
            TW::Hash::blake2b(outputData, outputData.size(), outputsHashPersonalization);
70 0
        copy(begin(hashOutputs), end(hashOutputs), back_inserter(data));
71 0
    } else {
72 0
        fill_n(back_inserter(data), 32, 0);
73
    }
74

75
    // JoinSplits
76 1
    auto hashJoinSplits = getJoinSplitsHash();
77 1
    data.insert(std::end(data), std::begin(hashJoinSplits), std::end(hashJoinSplits));
78

79
    // ShieldedSpends
80 1
    auto hashShieldedSpends = getShieldedSpendsHash();
81 1
    data.insert(std::end(data), std::begin(hashShieldedSpends), std::end(hashShieldedSpends));
82

83
    // ShieldedOutputs
84 1
    auto hashShieldedOutputs = getShieldedOutputsHash();
85 1
    data.insert(std::end(data), std::begin(hashShieldedOutputs), std::end(hashShieldedOutputs));
86

87
    // Locktime
88 1
    encode32LE(lockTime, data);
89

90
    // ExpiryHeight
91 1
    encode32LE(expiryHeight, data);
92

93
    // ValueBalance
94 1
    encode64LE(valueBalance, data);
95

96
    // Sighash type
97 1
    encode32LE(hashType, data);
98

99
    // The input being signed (replacing the scriptSig with scriptCode + amount)
100
    // The prevout may already be contained in hashPrevout, and the nSequence
101
    // may already be contain in hashSequence.
102 1
    reinterpret_cast<const Bitcoin::OutPoint&>(inputs[index].previousOutput).encode(data);
103 1
    scriptCode.encode(data);
104

105 1
    encode64LE(amount, data);
106 1
    encode32LE(inputs[index].sequence, data);
107

108 1
    return data;
109
}
110

111 1
Data Transaction::getPrevoutHash() const {
112 1
    auto data = Data{};
113 1
    for (auto& input : inputs) {
114 1
        auto& outpoint = input.previousOutput;
115 1
        outpoint.encode(data);
116
    }
117 1
    auto hash = TW::Hash::blake2b(data, 32, prevoutsHashPersonalization);
118 1
    return hash;
119
}
120

121 1
Data Transaction::getSequenceHash() const {
122 1
    auto data = Data{};
123 1
    for (auto& input : inputs) {
124 1
        encode32LE(input.sequence, data);
125
    }
126 1
    auto hash = TW::Hash::blake2b(data, 32, sequenceHashPersonalization);
127 1
    return hash;
128
}
129

130 1
Data Transaction::getOutputsHash() const {
131 1
    auto data = Data{};
132 1
    for (auto& output : outputs) {
133 1
        output.encode(data);
134
    }
135 1
    auto hash = TW::Hash::blake2b(data, 32, outputsHashPersonalization);
136 1
    return hash;
137
}
138

139 1
Data Transaction::getJoinSplitsHash() const {
140 1
    Data vec(32, 0);
141 1
    return vec;
142
}
143

144 1
Data Transaction::getShieldedSpendsHash() const {
145 1
    Data vec(32, 0);
146 1
    return vec;
147
}
148

149 1
Data Transaction::getShieldedOutputsHash() const {
150 1
    Data vec(32, 0);
151 1
    return vec;
152
}
153

154 1
void Transaction::encode(Data& data) const {
155 1
    encode32LE(version, data);
156 1
    encode32LE(versionGroupId, data);
157

158
    // vin
159 1
    encodeVarInt(inputs.size(), data);
160 1
    for (auto& input : inputs) {
161 1
        input.encode(data);
162
    }
163

164
    // vout
165 1
    encodeVarInt(outputs.size(), data);
166 1
    for (auto& output : outputs) {
167 1
        output.encode(data);
168
    }
169

170 1
    encode32LE(lockTime, data);
171 1
    encode32LE(expiryHeight, data);
172 1
    encode64LE(valueBalance, data);
173

174
    // vShieldedSpend
175 1
    encodeVarInt(0, data);
176
    // vShieldedOutput
177 1
    encodeVarInt(0, data);
178
    // vJoinSplit
179 1
    encodeVarInt(0, data);
180
}
181

182 1
Data Transaction::getSignatureHash(const Bitcoin::Script& scriptCode, size_t index,
183
                                   enum TWBitcoinSigHashType hashType, uint64_t amount,
184
                                   Bitcoin::SignatureVersion version) const {
185 1
    Data personalization;
186 1
    personalization.reserve(16);
187 1
    std::copy(sigHashPersonalization.begin(), sigHashPersonalization.begin() + 12,
188 1
              std::back_inserter(personalization));
189 1
    std::copy(branchId.begin(), branchId.end(), std::back_inserter(personalization));
190 1
    auto preimage = getPreImage(scriptCode, index, hashType, amount);
191 1
    auto hash = Hash::blake2b(preimage, 32, personalization);
192 1
    return hash;
193
}
194

195 1
Bitcoin::Proto::Transaction Transaction::proto() const {
196 1
    auto protoTx = Bitcoin::Proto::Transaction();
197 1
    protoTx.set_version(version);
198 1
    protoTx.set_locktime(lockTime);
199

200 1
    for (const auto& input : inputs) {
201 1
        auto protoInput = protoTx.add_inputs();
202 1
        protoInput->mutable_previousoutput()->set_hash(input.previousOutput.hash.data(),
203 1
                                                       input.previousOutput.hash.size());
204 1
        protoInput->mutable_previousoutput()->set_index(input.previousOutput.index);
205 1
        protoInput->set_sequence(input.sequence);
206 1
        protoInput->set_script(input.script.bytes.data(), input.script.bytes.size());
207
    }
208

209 1
    for (const auto& output : outputs) {
210 1
        auto protoOutput = protoTx.add_outputs();
211 1
        protoOutput->set_value(output.value);
212 1
        protoOutput->set_script(output.script.bytes.data(), output.script.bytes.size());
213
    }
214

215 1
    return protoTx;
216
}

Read our documentation on viewing source code .

Loading