From 6eea48bf965bfbd7d9b8e12e5f482ee229987ed7 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Tue, 8 May 2018 14:23:09 -0600 Subject: [PATCH 1/4] Remove unnecessary IsCoinbase() check. Coinbases are guaranteed to have empty vjoinsplit. --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index f6c211c3b..f83175dec 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -953,7 +953,7 @@ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, REJECT_INVALID, "bad-txns-oversize"); } - if (!(tx.IsCoinBase() || tx.vjoinsplit.empty())) { + if (!tx.vjoinsplit.empty()) { auto consensusBranchId = CurrentEpochBranchId(nHeight, Params().GetConsensus()); // Empty output script. CScript scriptCode; From 55fabd827274d437e08fb2d3cb0f6beac01bec25 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Tue, 8 May 2018 14:28:01 -0600 Subject: [PATCH 2/4] Refactor so that dataToBeSigned can be used later in the function for other purposes. --- src/main.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index f83175dec..d4e8fed27 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -953,18 +953,23 @@ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, REJECT_INVALID, "bad-txns-oversize"); } - if (!tx.vjoinsplit.empty()) { + uint256 dataToBeSigned; + + if (!tx.vjoinsplit.empty()) + { auto consensusBranchId = CurrentEpochBranchId(nHeight, Params().GetConsensus()); // Empty output script. CScript scriptCode; - uint256 dataToBeSigned; try { dataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); } catch (std::logic_error ex) { return state.DoS(100, error("CheckTransaction(): error computing signature hash"), REJECT_INVALID, "error-computing-signature-hash"); } + } + if (!tx.vjoinsplit.empty()) + { BOOST_STATIC_ASSERT(crypto_sign_PUBLICKEYBYTES == 32); // We rely on libsodium to check that the signature is canonical. From 531fcc88da6d87b8ea81be9edf50d332793e662c Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Tue, 8 May 2018 14:29:58 -0600 Subject: [PATCH 3/4] Update to latest librustzcash --- depends/packages/librustzcash.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depends/packages/librustzcash.mk b/depends/packages/librustzcash.mk index 96f3143d1..b15857fa5 100644 --- a/depends/packages/librustzcash.mk +++ b/depends/packages/librustzcash.mk @@ -3,8 +3,8 @@ $(package)_version=0.1 $(package)_download_path=https://github.com/zcash/$(package)/archive/ $(package)_file_name=$(package)-$($(package)_git_commit).tar.gz $(package)_download_file=$($(package)_git_commit).tar.gz -$(package)_sha256_hash=c5442a57d8961aab12fd395a5004edbb96b973511fab3949a087faa2a865a002 -$(package)_git_commit=ef676eff5084d394e6c6eaf2b9d9817effe662a7 +$(package)_sha256_hash=65363973dfbdde3bc9cb4427724db399c201f580eb42fb02b0b86e043931c90b +$(package)_git_commit=5e220695e5961c8619a1095a3b9022509c6c9b9d $(package)_dependencies=rust $(rust_crates) $(package)_patches=cargo.config From b4db32f53c7237f619365de677bf5d348b5c81d6 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Tue, 8 May 2018 14:28:55 -0600 Subject: [PATCH 4/4] Check Sapling Spend/Output proofs and signatures. --- src/main.cpp | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index d4e8fed27..3a69a87db 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -47,6 +47,8 @@ using namespace std; # error "Zcash cannot be compiled without assertions." #endif +#include "librustzcash.h" + /** * Global state */ @@ -955,7 +957,9 @@ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, uint256 dataToBeSigned; - if (!tx.vjoinsplit.empty()) + if (!tx.vjoinsplit.empty() || + !tx.vShieldedSpend.empty() || + !tx.vShieldedOutput.empty()) { auto consensusBranchId = CurrentEpochBranchId(nHeight, Params().GetConsensus()); // Empty output script. @@ -982,6 +986,59 @@ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature"); } } + + if (!tx.vShieldedSpend.empty() || + !tx.vShieldedOutput.empty()) + { + auto ctx = librustzcash_sapling_verification_ctx_init(); + + for (const SpendDescription &spend : tx.vShieldedSpend) { + if (!librustzcash_sapling_check_spend( + ctx, + spend.cv.begin(), + spend.anchor.begin(), + spend.nullifier.begin(), + spend.rk.begin(), + spend.zkproof.begin(), + spend.spendAuthSig.begin(), + dataToBeSigned.begin() + )) + { + librustzcash_sapling_verification_ctx_free(ctx); + return state.DoS(100, error("ContextualCheckTransaction(): Sapling spend description invalid"), + REJECT_INVALID, "bad-txns-sapling-spend-description-invalid"); + } + } + + for (const OutputDescription &output : tx.vShieldedOutput) { + if (!librustzcash_sapling_check_output( + ctx, + output.cv.begin(), + output.cm.begin(), + output.ephemeralKey.begin(), + output.zkproof.begin() + )) + { + librustzcash_sapling_verification_ctx_free(ctx); + return state.DoS(100, error("ContextualCheckTransaction(): Sapling output description invalid"), + REJECT_INVALID, "bad-txns-sapling-output-description-invalid"); + } + } + + if (!librustzcash_sapling_final_check( + ctx, + tx.valueBalance, + tx.bindingSig.begin(), + dataToBeSigned.begin() + )) + { + librustzcash_sapling_verification_ctx_free(ctx); + return state.DoS(100, error("ContextualCheckTransaction(): Sapling binding signature invalid"), + REJECT_INVALID, "bad-txns-sapling-binding-signature-invalid"); + } + + librustzcash_sapling_verification_ctx_free(ctx); + } return true; }