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 99 : SpendDescriptionInfo::SpendDescriptionInfo(const libzcash::SaplingExpandedSpendingKey& _expsk,
17 : const libzcash::SaplingNote& _note,
18 : const uint256& _anchor,
19 99 : const SaplingWitness& _witness):
20 : expsk(_expsk),
21 : note(_note),
22 : anchor(_anchor),
23 198 : witness(_witness)
24 : {
25 99 : librustzcash_sapling_generate_r(alpha.begin());
26 99 : }
27 :
28 1323 : Optional<OutputDescription> OutputDescriptionInfo::Build(void* ctx) {
29 2646 : auto cmu = this->note.cmu();
30 1323 : if (!cmu) {
31 0 : return nullopt;
32 : }
33 :
34 2646 : libzcash::SaplingNotePlaintext notePlaintext(this->note, this->memo);
35 :
36 2646 : auto res = notePlaintext.encrypt(this->note.pk_d);
37 1323 : if (!res) {
38 0 : return nullopt;
39 : }
40 1323 : auto enc = res.get();
41 1323 : auto encryptor = enc.second;
42 :
43 1323 : libzcash::SaplingPaymentAddress address(this->note.d, this->note.pk_d);
44 2646 : CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
45 1323 : ss << address;
46 2646 : std::vector<unsigned char> addressBytes(ss.begin(), ss.end());
47 :
48 1323 : OutputDescription odesc;
49 1323 : if (!librustzcash_sapling_output_proof(
50 : ctx,
51 1323 : encryptor.get_esk().begin(),
52 1323 : addressBytes.data(),
53 1323 : this->note.r.begin(),
54 : this->note.value(),
55 : odesc.cv.begin(),
56 : odesc.zkproof.begin())) {
57 0 : return nullopt;
58 : }
59 :
60 1323 : odesc.cmu = *cmu;
61 1323 : odesc.ephemeralKey = encryptor.get_epk();
62 1323 : odesc.encCiphertext = enc.first;
63 :
64 1323 : libzcash::SaplingOutgoingPlaintext outPlaintext(this->note.pk_d, encryptor.get_esk());
65 1323 : odesc.outCiphertext = outPlaintext.encrypt(
66 1323 : this->ovk,
67 : odesc.cv,
68 : odesc.cmu,
69 1323 : encryptor);
70 :
71 1323 : return odesc;
72 : }
73 :
74 : // Dummy constants used during fee-calculation loop
75 479 : static OutputDescription CreateDummyOD()
76 : {
77 479 : OutputDescription dummyOD;
78 479 : dummyOD.cv = UINT256_MAX;
79 479 : dummyOD.cmu = UINT256_MAX;
80 479 : dummyOD.ephemeralKey = UINT256_MAX;
81 479 : dummyOD.encCiphertext = {{0xff}};
82 479 : dummyOD.outCiphertext = {{0xff}};
83 479 : dummyOD.zkproof = {{0xff}};
84 479 : return dummyOD;
85 : }
86 479 : static SpendDescription CreateDummySD()
87 : {
88 479 : SpendDescription dummySD;
89 479 : dummySD.cv = UINT256_MAX;
90 479 : dummySD.anchor = UINT256_MAX;
91 479 : dummySD.nullifier = UINT256_MAX;
92 479 : dummySD.rk = UINT256_MAX;
93 479 : dummySD.zkproof = {{0xff}};
94 479 : dummySD.spendAuthSig = {{0xff}};
95 479 : 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 3373 : 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 3228 : Optional<CTransaction> TransactionBuilderResult::GetTx() {
120 3228 : 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 1248 : TransactionBuilder::TransactionBuilder(
133 : const Consensus::Params& _consensusParams,
134 1248 : CKeyStore* _keystore) :
135 : consensusParams(_consensusParams),
136 1248 : keystore(_keystore)
137 : {
138 1248 : Clear();
139 1248 : }
140 :
141 2302 : void TransactionBuilder::Clear()
142 : {
143 2302 : mtx = CMutableTransaction();
144 2302 : mtx.nVersion = CTransaction::TxVersion::SAPLING;
145 2302 : spends.clear();
146 2302 : outputs.clear();
147 2302 : tIns.clear();
148 2302 : saplingChangeAddr = nullopt;
149 2302 : tChangeAddr = nullopt;
150 2302 : fee = -1; // Verified in Build(). Must be set before.
151 2302 : }
152 :
153 100 : 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 100 : 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 100 : 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 99 : spends.emplace_back(expsk, note, anchor, witness);
170 99 : mtx.sapData->valueBalance += note.value();
171 99 : }
172 :
173 2396 : 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 2396 : if (mtx.nVersion < CTransaction::TxVersion::SAPLING) {
181 0 : throw std::runtime_error("TransactionBuilder cannot add Sapling output to pre-Sapling transaction");
182 : }
183 :
184 2396 : auto note = libzcash::SaplingNote(to, value);
185 2396 : outputs.emplace_back(ovk, note, memo);
186 2396 : mtx.sapData->valueBalance -= value;
187 2396 : }
188 :
189 2375 : void TransactionBuilder::AddTransparentInput(const COutPoint& utxo, const CScript& scriptPubKey, CAmount value)
190 : {
191 2375 : if (keystore == nullptr) {
192 1 : throw std::runtime_error("Cannot add transparent inputs to a TransactionBuilder without a keystore");
193 : }
194 :
195 2374 : mtx.vin.emplace_back(utxo);
196 2374 : tIns.emplace_back(scriptPubKey, value);
197 2374 : }
198 :
199 2116 : void TransactionBuilder::AddTransparentOutput(const CTxOut& out)
200 : {
201 4232 : std::vector<std::vector<unsigned char> > vSolutions;
202 2116 : txnouttype whichType;
203 2116 : if (!Solver(out.scriptPubKey, whichType, vSolutions))
204 1 : throw std::runtime_error("Transaction builder: invalid script for transparent output");
205 2115 : mtx.vout.push_back(out);
206 2115 : }
207 :
208 2078 : void TransactionBuilder::AddTransparentOutput(const CTxDestination& dest, CAmount value)
209 : {
210 4156 : AddTransparentOutput(CTxOut(value, GetScriptForDestination(dest)));
211 2077 : }
212 :
213 2290 : void TransactionBuilder::SetFee(CAmount _fee)
214 : {
215 2290 : this->fee = _fee;
216 2290 : }
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 2082 : void TransactionBuilder::SendChangeTo(const CTxDestination& changeAddr)
225 : {
226 2082 : if (!IsValidDestination(changeAddr)) {
227 1 : throw std::runtime_error("Invalid change address, not a valid taddr.");
228 : }
229 :
230 2081 : tChangeAddr = changeAddr;
231 2081 : saplingChangeAddr = nullopt;
232 2081 : }
233 :
234 1231 : TransactionBuilderResult TransactionBuilder::ProveAndSign()
235 : {
236 : //
237 : // Sapling spend descriptions
238 : //
239 1231 : if (!spends.empty() || !outputs.empty()) {
240 :
241 1228 : auto ctx = librustzcash_sapling_proving_ctx_init();
242 :
243 : // Create Sapling OutputDescriptions
244 2551 : for (auto output : outputs) {
245 : // Check this out here as well to provide better logging.
246 1323 : if (!output.note.cmu()) {
247 0 : librustzcash_sapling_proving_ctx_free(ctx);
248 0 : return TransactionBuilderResult("Output is invalid");
249 : }
250 :
251 2646 : auto odesc = output.Build(ctx);
252 1323 : if (!odesc) {
253 0 : librustzcash_sapling_proving_ctx_free(ctx);
254 0 : return TransactionBuilderResult("Failed to create output description");
255 : }
256 :
257 1323 : mtx.sapData->vShieldedOutput.push_back(odesc.get());
258 : }
259 :
260 : // Create Sapling SpendDescriptions
261 1301 : for (auto spend : spends) {
262 73 : auto cm = spend.note.cmu();
263 73 : auto nf = spend.note.nullifier(
264 146 : spend.expsk.full_viewing_key(), spend.witness.position());
265 73 : if (!cm || !nf) {
266 0 : librustzcash_sapling_proving_ctx_free(ctx);
267 0 : return TransactionBuilderResult("Spend is invalid");
268 : }
269 :
270 146 : CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
271 146 : ss << spend.witness.path();
272 146 : std::vector<unsigned char> witness(ss.begin(), ss.end());
273 :
274 73 : SpendDescription sdesc;
275 73 : if (!librustzcash_sapling_spend_proof(
276 : ctx,
277 73 : spend.expsk.full_viewing_key().ak.begin(),
278 73 : spend.expsk.nsk.begin(),
279 73 : spend.note.d.data(),
280 73 : spend.note.r.begin(),
281 73 : spend.alpha.begin(),
282 : spend.note.value(),
283 73 : spend.anchor.begin(),
284 73 : 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 73 : sdesc.anchor = spend.anchor;
293 73 : sdesc.nullifier = *nf;
294 73 : mtx.sapData->vShieldedSpend.push_back(sdesc);
295 : }
296 :
297 : //
298 : // Signatures
299 : //
300 :
301 : // Empty output script.
302 1228 : uint256 dataToBeSigned;
303 2456 : CScript scriptCode;
304 1228 : try {
305 1228 : 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 1301 : for (size_t i = 0; i < spends.size(); i++) {
313 73 : librustzcash_sapling_spend_sig(
314 73 : spends[i].expsk.ask.begin(),
315 73 : spends[i].alpha.begin(),
316 73 : dataToBeSigned.begin(),
317 73 : mtx.sapData->vShieldedSpend[i].spendAuthSig.data());
318 : }
319 :
320 2456 : librustzcash_sapling_binding_sig(
321 : ctx,
322 1228 : mtx.sapData->valueBalance,
323 1228 : dataToBeSigned.begin(),
324 1228 : mtx.sapData->bindingSig.data());
325 :
326 1228 : librustzcash_sapling_proving_ctx_free(ctx);
327 : }
328 :
329 : // Transparent signatures
330 2462 : CTransaction txNewConst(mtx);
331 2552 : for (int nIn = 0; nIn < (int) mtx.vin.size(); nIn++) {
332 2642 : auto tIn = tIns[nIn];
333 2642 : SignatureData sigdata;
334 1321 : bool signSuccess = ProduceSignature(
335 1321 : TransactionSignatureCreator(
336 : keystore, &txNewConst, nIn, tIn.value, SIGHASH_ALL),
337 : tIn.scriptPubKey, sigdata, SIGVERSION_SAPLING, false);
338 :
339 1321 : if (!signSuccess) {
340 0 : return TransactionBuilderResult("Failed to sign transaction");
341 : } else {
342 1321 : UpdateTransaction(mtx, nIn, sigdata);
343 : }
344 : }
345 :
346 1231 : return TransactionBuilderResult(CTransaction(mtx));
347 : }
348 :
349 2142 : TransactionBuilderResult TransactionBuilder::AddDummySignatures()
350 : {
351 2142 : if (!spends.empty() || !outputs.empty()) {
352 : // Add Dummy Sapling OutputDescriptions
353 4371 : for (unsigned int i = 0; i < outputs.size(); i++) {
354 2231 : mtx.sapData->vShieldedOutput.push_back(DUMMY_SHIELD_OUT);
355 : }
356 : // Add Dummy Sapling SpendDescriptions
357 2219 : for (unsigned int i = 0; i < spends.size(); i++) {
358 79 : mtx.sapData->vShieldedSpend.push_back(DUMMY_SHIELD_SPEND);
359 : }
360 : // Add Dummy Binding sig
361 2140 : mtx.sapData->bindingSig = DUMMY_SHIELD_BINDSIG;
362 : }
363 :
364 : // Add Dummmy Transparent signatures
365 4284 : CTransaction txNewConst(mtx);
366 4266 : for (int nIn = 0; nIn < (int) mtx.vin.size(); nIn++) {
367 4248 : auto tIn = tIns[nIn];
368 4248 : SignatureData sigdata;
369 2124 : if (!ProduceSignature(DummySignatureCreator(keystore), tIn.scriptPubKey, sigdata, SIGVERSION_SAPLING, false)) {
370 0 : return TransactionBuilderResult("Failed to sign transaction");
371 : } else {
372 2124 : UpdateTransaction(mtx, nIn, sigdata);
373 : }
374 : }
375 :
376 2142 : return TransactionBuilderResult(CTransaction(mtx));
377 : }
378 :
379 1086 : void TransactionBuilder::ClearProofsAndSignatures()
380 : {
381 : // Clear Sapling output descriptions
382 1086 : mtx.sapData->vShieldedOutput.clear();
383 :
384 : // Clear Sapling spend descriptions
385 1086 : mtx.sapData->vShieldedSpend.clear();
386 :
387 : // Clear Binding sig
388 1086 : mtx.sapData->bindingSig = {{0}};
389 :
390 : // Clear Transparent signatures
391 2158 : for (CTxIn& in : mtx.vin) in.scriptSig = CScript();
392 1086 : }
393 :
394 2291 : TransactionBuilderResult TransactionBuilder::Build(bool fDummySig)
395 : {
396 : //
397 : // Consistency checks
398 : //
399 : // Valid fee
400 2291 : if (fee < 0) {
401 0 : return TransactionBuilderResult("Fee cannot be negative");
402 : }
403 :
404 : // Valid change
405 2291 : CAmount change = mtx.sapData->valueBalance - fee;
406 4665 : for (auto& tIn : tIns) {
407 2374 : change += tIn.value;
408 : }
409 2333 : for (auto& tOut : mtx.vout) {
410 42 : change -= tOut.nValue;
411 : }
412 2291 : if (change < 0) {
413 6 : return TransactionBuilderResult("Change cannot be negative");
414 : }
415 :
416 : //
417 : // Change output
418 : //
419 :
420 2288 : if (change > 0) {
421 : // If we get here and the change is dust, add it to the fee
422 2149 : CAmount dustThreshold = (spends.empty() && outputs.empty()) ? GetDustThreshold(dustRelayFee)
423 2144 : : GetShieldedDustThreshold(dustRelayFee);
424 2149 : 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 2148 : if (saplingChangeAddr) {
429 1 : AddSaplingOutput(saplingChangeAddr->first, saplingChangeAddr->second, change);
430 2147 : } else if (tChangeAddr) {
431 : // tChangeAddr has already been validated.
432 2075 : 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 2287 : return fDummySig ? AddDummySignatures() : ProveAndSign();
449 : }
|