Line data Source code
1 : // Copyright (c) 2018-2020 The Zcash developers
2 : // Copyright (c) 2020-2021 The PIVX Core developers
3 : // Distributed under the MIT software license, see the accompanying
4 : // file COPYING or https://www.opensource.org/licenses/mit-license.php .
5 :
6 : #include "sapling/transaction_builder.h"
7 :
8 : #include "script/sign.h"
9 : #include "utilmoneystr.h"
10 : #include "consensus/upgrades.h"
11 : #include "policy/policy.h"
12 : #include "validation.h"
13 :
14 : #include <librustzcash.h>
15 :
16 98 : SpendDescriptionInfo::SpendDescriptionInfo(const libzcash::SaplingExpandedSpendingKey& _expsk,
17 : const libzcash::SaplingNote& _note,
18 : const uint256& _anchor,
19 98 : const SaplingWitness& _witness):
20 : expsk(_expsk),
21 : note(_note),
22 : anchor(_anchor),
23 196 : witness(_witness)
24 : {
25 98 : librustzcash_sapling_generate_r(alpha.begin());
26 98 : }
27 :
28 327 : Optional<OutputDescription> OutputDescriptionInfo::Build(void* ctx) {
29 654 : auto cmu = this->note.cmu();
30 327 : if (!cmu) {
31 0 : return nullopt;
32 : }
33 :
34 654 : libzcash::SaplingNotePlaintext notePlaintext(this->note, this->memo);
35 :
36 654 : auto res = notePlaintext.encrypt(this->note.pk_d);
37 327 : if (!res) {
38 0 : return nullopt;
39 : }
40 327 : auto enc = res.get();
41 327 : auto encryptor = enc.second;
42 :
43 327 : libzcash::SaplingPaymentAddress address(this->note.d, this->note.pk_d);
44 654 : CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
45 327 : ss << address;
46 654 : std::vector<unsigned char> addressBytes(ss.begin(), ss.end());
47 :
48 327 : OutputDescription odesc;
49 327 : if (!librustzcash_sapling_output_proof(
50 : ctx,
51 327 : encryptor.get_esk().begin(),
52 327 : addressBytes.data(),
53 327 : this->note.r.begin(),
54 : this->note.value(),
55 : odesc.cv.begin(),
56 : odesc.zkproof.begin())) {
57 0 : return nullopt;
58 : }
59 :
60 327 : odesc.cmu = *cmu;
61 327 : odesc.ephemeralKey = encryptor.get_epk();
62 327 : odesc.encCiphertext = enc.first;
63 :
64 327 : libzcash::SaplingOutgoingPlaintext outPlaintext(this->note.pk_d, encryptor.get_esk());
65 327 : odesc.outCiphertext = outPlaintext.encrypt(
66 327 : this->ovk,
67 : odesc.cv,
68 : odesc.cmu,
69 327 : encryptor);
70 :
71 327 : return odesc;
72 : }
73 :
74 : // Dummy constants used during fee-calculation loop
75 416 : static OutputDescription CreateDummyOD()
76 : {
77 416 : OutputDescription dummyOD;
78 416 : dummyOD.cv = UINT256_MAX;
79 416 : dummyOD.cmu = UINT256_MAX;
80 416 : dummyOD.ephemeralKey = UINT256_MAX;
81 416 : dummyOD.encCiphertext = {{0xff}};
82 416 : dummyOD.outCiphertext = {{0xff}};
83 416 : dummyOD.zkproof = {{0xff}};
84 416 : return dummyOD;
85 : }
86 416 : static SpendDescription CreateDummySD()
87 : {
88 416 : SpendDescription dummySD;
89 416 : dummySD.cv = UINT256_MAX;
90 416 : dummySD.anchor = UINT256_MAX;
91 416 : dummySD.nullifier = UINT256_MAX;
92 416 : dummySD.rk = UINT256_MAX;
93 416 : dummySD.zkproof = {{0xff}};
94 416 : dummySD.spendAuthSig = {{0xff}};
95 416 : return dummySD;
96 : }
97 :
98 : const OutputDescription DUMMY_SHIELD_OUT = CreateDummyOD();
99 : const SpendDescription DUMMY_SHIELD_SPEND = CreateDummySD();
100 : const SaplingTxData::binding_sig_t DUMMY_SHIELD_BINDSIG = {{0xff}};
101 :
102 :
103 379 : TransactionBuilderResult::TransactionBuilderResult(const CTransaction& tx) : maybeTx(tx) {}
104 :
105 4 : TransactionBuilderResult::TransactionBuilderResult(const std::string& error) : maybeError(error) {}
106 :
107 1 : bool TransactionBuilderResult::IsTx() { return maybeTx != nullopt; }
108 :
109 0 : bool TransactionBuilderResult::IsError() { return maybeError != nullopt; }
110 :
111 144 : CTransaction TransactionBuilderResult::GetTxOrThrow() {
112 144 : if (maybeTx) {
113 144 : return maybeTx.get();
114 : } else {
115 0 : throw std::runtime_error("Failed to build transaction: " + GetError());
116 : }
117 : }
118 :
119 234 : Optional<CTransaction> TransactionBuilderResult::GetTx() {
120 234 : return maybeTx;
121 : }
122 :
123 4 : std::string TransactionBuilderResult::GetError() {
124 4 : if (maybeError) {
125 4 : return maybeError.get();
126 : } else {
127 : // This can only happen if isTx() is true in which case we should not call getError()
128 0 : throw std::runtime_error("getError() was called in TransactionBuilderResult, but the result was not initialized as an error.");
129 : }
130 : }
131 :
132 251 : TransactionBuilder::TransactionBuilder(
133 : const Consensus::Params& _consensusParams,
134 251 : CKeyStore* _keystore) :
135 : consensusParams(_consensusParams),
136 251 : keystore(_keystore)
137 : {
138 251 : Clear();
139 251 : }
140 :
141 305 : void TransactionBuilder::Clear()
142 : {
143 305 : mtx = CMutableTransaction();
144 305 : mtx.nVersion = CTransaction::TxVersion::SAPLING;
145 305 : spends.clear();
146 305 : outputs.clear();
147 305 : tIns.clear();
148 305 : saplingChangeAddr = nullopt;
149 305 : tChangeAddr = nullopt;
150 305 : fee = -1; // Verified in Build(). Must be set before.
151 305 : }
152 :
153 99 : void TransactionBuilder::AddSaplingSpend(
154 : const libzcash::SaplingExpandedSpendingKey& expsk,
155 : const libzcash::SaplingNote& note,
156 : const uint256& anchor,
157 : const SaplingWitness& witness)
158 : {
159 : // Sanity check: cannot add Sapling spend to pre-Sapling transaction
160 99 : if (mtx.nVersion < CTransaction::TxVersion::SAPLING) {
161 0 : throw std::runtime_error("TransactionBuilder cannot add Sapling spend to pre-Sapling transaction");
162 : }
163 :
164 : // Consistency check: all anchors must equal the first one
165 99 : if (spends.size() > 0 && spends[0].anchor != anchor) {
166 1 : throw std::runtime_error("Anchor does not match previously-added Sapling spends.");
167 : }
168 :
169 98 : spends.emplace_back(expsk, note, anchor, witness);
170 98 : mtx.sapData->valueBalance += note.value();
171 98 : }
172 :
173 400 : void TransactionBuilder::AddSaplingOutput(
174 : const uint256& ovk,
175 : const libzcash::SaplingPaymentAddress& to,
176 : CAmount value,
177 : const std::array<unsigned char, ZC_MEMO_SIZE>& memo)
178 : {
179 : // Sanity check: cannot add Sapling output to pre-Sapling transaction
180 400 : if (mtx.nVersion < CTransaction::TxVersion::SAPLING) {
181 0 : throw std::runtime_error("TransactionBuilder cannot add Sapling output to pre-Sapling transaction");
182 : }
183 :
184 400 : auto note = libzcash::SaplingNote(to, value);
185 400 : outputs.emplace_back(ovk, note, memo);
186 400 : mtx.sapData->valueBalance -= value;
187 400 : }
188 :
189 374 : void TransactionBuilder::AddTransparentInput(const COutPoint& utxo, const CScript& scriptPubKey, CAmount value)
190 : {
191 374 : if (keystore == nullptr) {
192 1 : throw std::runtime_error("Cannot add transparent inputs to a TransactionBuilder without a keystore");
193 : }
194 :
195 373 : mtx.vin.emplace_back(utxo);
196 373 : tIns.emplace_back(scriptPubKey, value);
197 373 : }
198 :
199 118 : void TransactionBuilder::AddTransparentOutput(const CTxOut& out)
200 : {
201 236 : std::vector<std::vector<unsigned char> > vSolutions;
202 118 : txnouttype whichType;
203 118 : if (!Solver(out.scriptPubKey, whichType, vSolutions))
204 1 : throw std::runtime_error("Transaction builder: invalid script for transparent output");
205 117 : mtx.vout.push_back(out);
206 117 : }
207 :
208 78 : void TransactionBuilder::AddTransparentOutput(const CTxDestination& dest, CAmount value)
209 : {
210 156 : AddTransparentOutput(CTxOut(value, GetScriptForDestination(dest)));
211 77 : }
212 :
213 293 : void TransactionBuilder::SetFee(CAmount _fee)
214 : {
215 293 : this->fee = _fee;
216 293 : }
217 :
218 1 : void TransactionBuilder::SendChangeTo(const libzcash::SaplingPaymentAddress& changeAddr, const uint256& ovk)
219 : {
220 1 : saplingChangeAddr = std::make_pair(ovk, changeAddr);
221 1 : tChangeAddr = nullopt;
222 1 : }
223 :
224 82 : void TransactionBuilder::SendChangeTo(const CTxDestination& changeAddr)
225 : {
226 82 : if (!IsValidDestination(changeAddr)) {
227 1 : throw std::runtime_error("Invalid change address, not a valid taddr.");
228 : }
229 :
230 81 : tChangeAddr = changeAddr;
231 81 : saplingChangeAddr = nullopt;
232 81 : }
233 :
234 234 : TransactionBuilderResult TransactionBuilder::ProveAndSign()
235 : {
236 : //
237 : // Sapling spend descriptions
238 : //
239 234 : if (!spends.empty() || !outputs.empty()) {
240 :
241 231 : auto ctx = librustzcash_sapling_proving_ctx_init();
242 :
243 : // Create Sapling OutputDescriptions
244 558 : for (auto output : outputs) {
245 : // Check this out here as well to provide better logging.
246 327 : if (!output.note.cmu()) {
247 0 : librustzcash_sapling_proving_ctx_free(ctx);
248 0 : return TransactionBuilderResult("Output is invalid");
249 : }
250 :
251 654 : auto odesc = output.Build(ctx);
252 327 : if (!odesc) {
253 0 : librustzcash_sapling_proving_ctx_free(ctx);
254 0 : return TransactionBuilderResult("Failed to create output description");
255 : }
256 :
257 327 : mtx.sapData->vShieldedOutput.push_back(odesc.get());
258 : }
259 :
260 : // Create Sapling SpendDescriptions
261 303 : for (auto spend : spends) {
262 72 : auto cm = spend.note.cmu();
263 72 : auto nf = spend.note.nullifier(
264 144 : spend.expsk.full_viewing_key(), spend.witness.position());
265 72 : if (!cm || !nf) {
266 0 : librustzcash_sapling_proving_ctx_free(ctx);
267 0 : return TransactionBuilderResult("Spend is invalid");
268 : }
269 :
270 144 : CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
271 144 : ss << spend.witness.path();
272 144 : std::vector<unsigned char> witness(ss.begin(), ss.end());
273 :
274 72 : SpendDescription sdesc;
275 72 : if (!librustzcash_sapling_spend_proof(
276 : ctx,
277 72 : spend.expsk.full_viewing_key().ak.begin(),
278 72 : spend.expsk.nsk.begin(),
279 72 : spend.note.d.data(),
280 72 : spend.note.r.begin(),
281 72 : spend.alpha.begin(),
282 : spend.note.value(),
283 72 : spend.anchor.begin(),
284 72 : witness.data(),
285 : sdesc.cv.begin(),
286 : sdesc.rk.begin(),
287 : sdesc.zkproof.data())) {
288 0 : librustzcash_sapling_proving_ctx_free(ctx);
289 0 : return TransactionBuilderResult("Spend proof failed");
290 : }
291 :
292 72 : sdesc.anchor = spend.anchor;
293 72 : sdesc.nullifier = *nf;
294 72 : mtx.sapData->vShieldedSpend.push_back(sdesc);
295 : }
296 :
297 : //
298 : // Signatures
299 : //
300 :
301 : // Empty output script.
302 231 : uint256 dataToBeSigned;
303 462 : CScript scriptCode;
304 231 : try {
305 231 : dataToBeSigned = SignatureHash(scriptCode, mtx, NOT_AN_INPUT, SIGHASH_ALL, 0, SIGVERSION_SAPLING);
306 0 : } catch (const std::logic_error& ex) {
307 0 : librustzcash_sapling_proving_ctx_free(ctx);
308 0 : return TransactionBuilderResult("Could not construct signature hash: " + std::string(ex.what()));
309 : }
310 :
311 : // Create Sapling spendAuth and binding signatures
312 303 : for (size_t i = 0; i < spends.size(); i++) {
313 72 : librustzcash_sapling_spend_sig(
314 72 : spends[i].expsk.ask.begin(),
315 72 : spends[i].alpha.begin(),
316 72 : dataToBeSigned.begin(),
317 72 : mtx.sapData->vShieldedSpend[i].spendAuthSig.data());
318 : }
319 :
320 462 : librustzcash_sapling_binding_sig(
321 : ctx,
322 231 : mtx.sapData->valueBalance,
323 231 : dataToBeSigned.begin(),
324 231 : mtx.sapData->bindingSig.data());
325 :
326 231 : librustzcash_sapling_proving_ctx_free(ctx);
327 : }
328 :
329 : // Transparent signatures
330 468 : CTransaction txNewConst(mtx);
331 554 : for (int nIn = 0; nIn < (int) mtx.vin.size(); nIn++) {
332 640 : auto tIn = tIns[nIn];
333 640 : SignatureData sigdata;
334 320 : bool signSuccess = ProduceSignature(
335 320 : TransactionSignatureCreator(
336 : keystore, &txNewConst, nIn, tIn.value, SIGHASH_ALL),
337 : tIn.scriptPubKey, sigdata, SIGVERSION_SAPLING, false);
338 :
339 320 : if (!signSuccess) {
340 0 : return TransactionBuilderResult("Failed to sign transaction");
341 : } else {
342 320 : UpdateTransaction(mtx, nIn, sigdata);
343 : }
344 : }
345 :
346 234 : return TransactionBuilderResult(CTransaction(mtx));
347 : }
348 :
349 145 : TransactionBuilderResult TransactionBuilder::AddDummySignatures()
350 : {
351 145 : if (!spends.empty() || !outputs.empty()) {
352 : // Add Dummy Sapling OutputDescriptions
353 378 : for (unsigned int i = 0; i < outputs.size(); i++) {
354 235 : mtx.sapData->vShieldedOutput.push_back(DUMMY_SHIELD_OUT);
355 : }
356 : // Add Dummy Sapling SpendDescriptions
357 221 : for (unsigned int i = 0; i < spends.size(); i++) {
358 78 : mtx.sapData->vShieldedSpend.push_back(DUMMY_SHIELD_SPEND);
359 : }
360 : // Add Dummy Binding sig
361 143 : mtx.sapData->bindingSig = DUMMY_SHIELD_BINDSIG;
362 : }
363 :
364 : // Add Dummmy Transparent signatures
365 290 : CTransaction txNewConst(mtx);
366 268 : for (int nIn = 0; nIn < (int) mtx.vin.size(); nIn++) {
367 246 : auto tIn = tIns[nIn];
368 246 : SignatureData sigdata;
369 123 : if (!ProduceSignature(DummySignatureCreator(keystore), tIn.scriptPubKey, sigdata, SIGVERSION_SAPLING, false)) {
370 0 : return TransactionBuilderResult("Failed to sign transaction");
371 : } else {
372 123 : UpdateTransaction(mtx, nIn, sigdata);
373 : }
374 : }
375 :
376 145 : return TransactionBuilderResult(CTransaction(mtx));
377 : }
378 :
379 89 : void TransactionBuilder::ClearProofsAndSignatures()
380 : {
381 : // Clear Sapling output descriptions
382 89 : mtx.sapData->vShieldedOutput.clear();
383 :
384 : // Clear Sapling spend descriptions
385 89 : mtx.sapData->vShieldedSpend.clear();
386 :
387 : // Clear Binding sig
388 89 : mtx.sapData->bindingSig = {{0}};
389 :
390 : // Clear Transparent signatures
391 160 : for (CTxIn& in : mtx.vin) in.scriptSig = CScript();
392 89 : }
393 :
394 294 : TransactionBuilderResult TransactionBuilder::Build(bool fDummySig)
395 : {
396 : //
397 : // Consistency checks
398 : //
399 : // Valid fee
400 294 : if (fee < 0) {
401 0 : return TransactionBuilderResult("Fee cannot be negative");
402 : }
403 :
404 : // Valid change
405 294 : CAmount change = mtx.sapData->valueBalance - fee;
406 667 : for (auto& tIn : tIns) {
407 373 : change += tIn.value;
408 : }
409 338 : for (auto& tOut : mtx.vout) {
410 44 : change -= tOut.nValue;
411 : }
412 294 : if (change < 0) {
413 6 : return TransactionBuilderResult("Change cannot be negative");
414 : }
415 :
416 : //
417 : // Change output
418 : //
419 :
420 291 : if (change > 0) {
421 : // If we get here and the change is dust, add it to the fee
422 149 : CAmount dustThreshold = (spends.empty() && outputs.empty()) ? GetDustThreshold(dustRelayFee)
423 144 : : GetShieldedDustThreshold(dustRelayFee);
424 149 : if (change > dustThreshold) {
425 : // Send change to the specified change address. If no change address
426 : // was set, send change to the first Sapling address given as input
427 : // (A t-address can only be used as the change address if explicitly set.)
428 148 : if (saplingChangeAddr) {
429 1 : AddSaplingOutput(saplingChangeAddr->first, saplingChangeAddr->second, change);
430 147 : } else if (tChangeAddr) {
431 : // tChangeAddr has already been validated.
432 75 : AddTransparentOutput(*tChangeAddr, change);
433 72 : } else if (!spends.empty()) {
434 71 : auto fvk = spends[0].expsk.full_viewing_key();
435 71 : auto note = spends[0].note;
436 71 : libzcash::SaplingPaymentAddress changeAddr(note.d, note.pk_d);
437 71 : AddSaplingOutput(fvk.ovk, changeAddr, change);
438 : } else {
439 2 : return TransactionBuilderResult("Could not determine change address");
440 : }
441 : } else {
442 : // Not used after, but update for consistency
443 1 : fee += change;
444 1 : change = 0;
445 : }
446 : }
447 :
448 290 : return fDummySig ? AddDummySignatures() : ProveAndSign();
449 : }
|