|
12 | 12 | #include <pubkey.h>
|
13 | 13 | #include <script/script.h>
|
14 | 14 | #include <uint256.h>
|
| 15 | +extern "C" { |
| 16 | +#include <simplicity/elements/exec.h> |
| 17 | +#include <simplicity/errorCodes.h> |
| 18 | +} |
15 | 19 |
|
16 | 20 | typedef std::vector<unsigned char> valtype;
|
17 | 21 |
|
@@ -2596,6 +2600,76 @@ void PrecomputedTransactionData::Init(const T& txTo, std::vector<CTxOut>&& spent
|
2596 | 2600 | m_spent_scripts_single_hash = GetSpentScriptsSHA256(m_spent_outputs);
|
2597 | 2601 | m_spent_output_spk_single_hashes = GetSpentScriptPubKeysSHA256(m_spent_outputs);
|
2598 | 2602 | m_output_spk_single_hashes = GetOutputScriptPubKeysSHA256(txTo);
|
| 2603 | + |
| 2604 | + std::vector<rawBuffer> simplicityRawAnnex(txTo.witness.vtxinwit.size()); |
| 2605 | + std::vector<rawInput> simplicityRawInput(txTo.vin.size()); |
| 2606 | + for (size_t i = 0; i < txTo.vin.size(); ++i) { |
| 2607 | + simplicityRawInput[i].prevTxid = txTo.vin[i].prevout.hash.begin(); |
| 2608 | + simplicityRawInput[i].prevIx = txTo.vin[i].prevout.n; |
| 2609 | + simplicityRawInput[i].sequence = txTo.vin[i].nSequence; |
| 2610 | + simplicityRawInput[i].txo.asset = m_spent_outputs[i].nAsset.vchCommitment.empty() ? NULL : m_spent_outputs[i].nAsset.vchCommitment.data(); |
| 2611 | + simplicityRawInput[i].txo.value = m_spent_outputs[i].nValue.vchCommitment.empty() ? NULL : m_spent_outputs[i].nValue.vchCommitment.data(); |
| 2612 | + simplicityRawInput[i].txo.scriptPubKey.buf = m_spent_outputs[i].scriptPubKey.data(); |
| 2613 | + simplicityRawInput[i].txo.scriptPubKey.len = m_spent_outputs[i].scriptPubKey.size(); |
| 2614 | + simplicityRawInput[i].issuance.blindingNonce = txTo.vin[i].assetIssuance.assetBlindingNonce.begin(); |
| 2615 | + simplicityRawInput[i].issuance.assetEntropy = txTo.vin[i].assetIssuance.assetEntropy.begin(); |
| 2616 | + simplicityRawInput[i].issuance.amount = txTo.vin[i].assetIssuance.nAmount.vchCommitment.empty() ? NULL : txTo.vin[i].assetIssuance.nAmount.vchCommitment.data(); |
| 2617 | + simplicityRawInput[i].issuance.inflationKeys = txTo.vin[i].assetIssuance.nInflationKeys.vchCommitment.empty() ? NULL : txTo.vin[i].assetIssuance.nInflationKeys.vchCommitment.data(); |
| 2618 | + simplicityRawInput[i].annex = NULL; |
| 2619 | + if (i < txTo.witness.vtxinwit.size()) { |
| 2620 | + Span<const valtype> stack{txTo.witness.vtxinwit[i].scriptWitness.stack}; |
| 2621 | + if (stack.size() >= 2 && !stack.back().empty() && stack.back()[0] == ANNEX_TAG) { |
| 2622 | + simplicityRawAnnex[i].buf = stack.back().data()+1; |
| 2623 | + simplicityRawAnnex[i].len = stack.back().size()-1; |
| 2624 | + simplicityRawInput[i].annex = &simplicityRawAnnex[i]; |
| 2625 | + } |
| 2626 | + simplicityRawInput[i].issuance.amountRangePrf.buf = txTo.witness.vtxinwit[i].vchIssuanceAmountRangeproof.data(); |
| 2627 | + simplicityRawInput[i].issuance.amountRangePrf.len = txTo.witness.vtxinwit[i].vchIssuanceAmountRangeproof.size(); |
| 2628 | + simplicityRawInput[i].issuance.inflationKeysRangePrf.buf = txTo.witness.vtxinwit[i].vchInflationKeysRangeproof.data(); |
| 2629 | + simplicityRawInput[i].issuance.inflationKeysRangePrf.len = txTo.witness.vtxinwit[i].vchInflationKeysRangeproof.size(); |
| 2630 | + assert(!txTo.vin[i].m_is_pegin || ( txTo.witness.vtxinwit[i].m_pegin_witness.stack.size() >= 4 && txTo.witness.vtxinwit[i].m_pegin_witness.stack[2].size() == 32)); |
| 2631 | + simplicityRawInput[i].pegin = txTo.vin[i].m_is_pegin ? txTo.witness.vtxinwit[i].m_pegin_witness.stack[2].data() : 0; |
| 2632 | + } else { |
| 2633 | + simplicityRawInput[i].issuance.amountRangePrf.buf = NULL; |
| 2634 | + simplicityRawInput[i].issuance.amountRangePrf.len = 0; |
| 2635 | + simplicityRawInput[i].issuance.inflationKeysRangePrf.buf = NULL; |
| 2636 | + simplicityRawInput[i].issuance.inflationKeysRangePrf.len = 0; |
| 2637 | + assert(!txTo.vin[i].m_is_pegin); |
| 2638 | + simplicityRawInput[i].pegin = 0; |
| 2639 | + } |
| 2640 | + } |
| 2641 | + |
| 2642 | + std::vector<rawOutput> simplicityRawOutput(txTo.vout.size()); |
| 2643 | + for (size_t i = 0; i < txTo.vout.size(); ++i) { |
| 2644 | + simplicityRawOutput[i].asset = txTo.vout[i].nAsset.vchCommitment.empty() ? NULL : txTo.vout[i].nAsset.vchCommitment.data(); |
| 2645 | + simplicityRawOutput[i].value = txTo.vout[i].nValue.vchCommitment.empty() ? NULL : txTo.vout[i].nValue.vchCommitment.data(); |
| 2646 | + simplicityRawOutput[i].nonce = txTo.vout[i].nNonce.vchCommitment.empty() ? NULL : txTo.vout[i].nNonce.vchCommitment.data(); |
| 2647 | + simplicityRawOutput[i].scriptPubKey.buf = txTo.vout[i].scriptPubKey.data(); |
| 2648 | + simplicityRawOutput[i].scriptPubKey.len = txTo.vout[i].scriptPubKey.size(); |
| 2649 | + if (i < txTo.witness.vtxoutwit.size()) { |
| 2650 | + simplicityRawOutput[i].surjectionProof.buf = txTo.witness.vtxoutwit[i].vchSurjectionproof.data(); |
| 2651 | + simplicityRawOutput[i].surjectionProof.len = txTo.witness.vtxoutwit[i].vchSurjectionproof.size(); |
| 2652 | + simplicityRawOutput[i].rangeProof.buf = txTo.witness.vtxoutwit[i].vchRangeproof.data(); |
| 2653 | + simplicityRawOutput[i].rangeProof.len = txTo.witness.vtxoutwit[i].vchRangeproof.size(); |
| 2654 | + } else { |
| 2655 | + simplicityRawOutput[i].surjectionProof.buf = NULL; |
| 2656 | + simplicityRawOutput[i].surjectionProof.len = 0; |
| 2657 | + simplicityRawOutput[i].rangeProof.buf = NULL; |
| 2658 | + simplicityRawOutput[i].rangeProof.len = 0; |
| 2659 | + } |
| 2660 | + } |
| 2661 | + |
| 2662 | + rawTransaction simplicityRawTx; |
| 2663 | + simplicityRawTx.txid = txTo.GetHash().begin(); |
| 2664 | + simplicityRawTx.input = simplicityRawInput.data(); |
| 2665 | + simplicityRawTx.numInputs = simplicityRawInput.size(); |
| 2666 | + simplicityRawTx.output = simplicityRawOutput.data(); |
| 2667 | + simplicityRawTx.numOutputs = simplicityRawOutput.size(); |
| 2668 | + simplicityRawTx.version = txTo.nVersion; |
| 2669 | + simplicityRawTx.lockTime = txTo.nLockTime; |
| 2670 | + |
| 2671 | + m_simplicity_tx_data = simplicity_elements_mallocTransaction(&simplicityRawTx); |
| 2672 | + |
2599 | 2673 | m_bip341_taproot_ready = true;
|
2600 | 2674 | }
|
2601 | 2675 | }
|
@@ -3038,6 +3112,51 @@ uint32_t GenericTransactionSignatureChecker<T>::GetnIn() const
|
3038 | 3112 | return nIn;
|
3039 | 3113 | }
|
3040 | 3114 |
|
| 3115 | +template <class T> |
| 3116 | +bool GenericTransactionSignatureChecker<T>::CheckSimplicity(const valtype& program, const valtype& witness, const rawTapEnv& simplicityRawTap, int64_t budget, ScriptError* serror) const |
| 3117 | +{ |
| 3118 | + simplicity_err error; |
| 3119 | + tapEnv* simplicityTapEnv = simplicity_elements_mallocTapEnv(&simplicityRawTap); |
| 3120 | + |
| 3121 | + assert(txdata->m_simplicity_tx_data); |
| 3122 | + assert(simplicityTapEnv); |
| 3123 | + if (!simplicity_elements_execSimplicity(&error, 0, txdata->m_simplicity_tx_data, nIn, simplicityTapEnv, txdata->m_hash_genesis_block.data(), budget, 0, program.data(), program.size(), witness.data(), witness.size())) { |
| 3124 | + assert(!"simplicity_elements_execSimplicity internal error"); |
| 3125 | + } |
| 3126 | + free(simplicityTapEnv); |
| 3127 | + switch (error) { |
| 3128 | + case SIMPLICITY_NO_ERROR: return set_success(serror); |
| 3129 | + case SIMPLICITY_ERR_MALLOC: |
| 3130 | + case SIMPLICITY_ERR_NOT_YET_IMPLEMENTED: |
| 3131 | + assert(!"simplicity_elements_execSimplicity internal error"); |
| 3132 | + break; |
| 3133 | + case SIMPLICITY_ERR_DATA_OUT_OF_RANGE: return set_error(serror, SCRIPT_ERR_SIMPLICITY_DATA_OUT_OF_RANGE); |
| 3134 | + case SIMPLICITY_ERR_DATA_OUT_OF_ORDER: return set_error(serror, SCRIPT_ERR_SIMPLICITY_DATA_OUT_OF_ORDER); |
| 3135 | + case SIMPLICITY_ERR_FAIL_CODE: return set_error(serror, SCRIPT_ERR_SIMPLICITY_FAIL_CODE); |
| 3136 | + case SIMPLICITY_ERR_STOP_CODE: return set_error(serror, SCRIPT_ERR_SIMPLICITY_STOP_CODE); |
| 3137 | + case SIMPLICITY_ERR_HIDDEN: return set_error(serror, SCRIPT_ERR_SIMPLICITY_HIDDEN); |
| 3138 | + case SIMPLICITY_ERR_BITSTREAM_EOF: return set_error(serror, SCRIPT_ERR_SIMPLICITY_BITSTREAM_EOF); |
| 3139 | + case SIMPLICITY_ERR_BITSTREAM_TRAILING_BYTES: return set_error(serror, SCRIPT_ERR_SIMPLICITY_BITSTREAM_TRAILING_BYTES); |
| 3140 | + case SIMPLICITY_ERR_BITSTREAM_ILLEGAL_PADDING: return set_error(serror, SCRIPT_ERR_SIMPLICITY_BITSTREAM_ILLEGAL_PADDING); |
| 3141 | + case SIMPLICITY_ERR_TYPE_INFERENCE_UNIFICATION: return set_error(serror, SCRIPT_ERR_SIMPLICITY_TYPE_INFERENCE_UNIFICATION); |
| 3142 | + case SIMPLICITY_ERR_TYPE_INFERENCE_OCCURS_CHECK: return set_error(serror, SCRIPT_ERR_SIMPLICITY_TYPE_INFERENCE_OCCURS_CHECK); |
| 3143 | + case SIMPLICITY_ERR_TYPE_INFERENCE_NOT_PROGRAM: return set_error(serror, SCRIPT_ERR_SIMPLICITY_TYPE_INFERENCE_NOT_PROGRAM); |
| 3144 | + case SIMPLICITY_ERR_WITNESS_EOF: return set_error(serror, SCRIPT_ERR_SIMPLICITY_WITNESS_EOF); |
| 3145 | + case SIMPLICITY_ERR_WITNESS_TRAILING_BYTES: return set_error(serror, SCRIPT_ERR_SIMPLICITY_WITNESS_TRAILING_BYTES); |
| 3146 | + case SIMPLICITY_ERR_WITNESS_ILLEGAL_PADDING: return set_error(serror, SCRIPT_ERR_SIMPLICITY_WITNESS_ILLEGAL_PADDING); |
| 3147 | + case SIMPLICITY_ERR_UNSHARED_SUBEXPRESSION: return set_error(serror, SCRIPT_ERR_SIMPLICITY_UNSHARED_SUBEXPRESSION); |
| 3148 | + case SIMPLICITY_ERR_CMR: return set_error(serror, SCRIPT_ERR_SIMPLICITY_CMR); |
| 3149 | + case SIMPLICITY_ERR_EXEC_BUDGET: return set_error(serror, SCRIPT_ERR_SIMPLICITY_EXEC_BUDGET); |
| 3150 | + case SIMPLICITY_ERR_EXEC_MEMORY: return set_error(serror, SCRIPT_ERR_SIMPLICITY_EXEC_MEMORY); |
| 3151 | + case SIMPLICITY_ERR_EXEC_JET: return set_error(serror, SCRIPT_ERR_SIMPLICITY_EXEC_JET); |
| 3152 | + case SIMPLICITY_ERR_EXEC_ASSERT: return set_error(serror, SCRIPT_ERR_SIMPLICITY_EXEC_ASSERT); |
| 3153 | + case SIMPLICITY_ERR_ANTIDOS: return set_error(serror, SCRIPT_ERR_SIMPLICITY_ANTIDOS); |
| 3154 | + case SIMPLICITY_ERR_HIDDEN_ROOT: return set_error(serror, SCRIPT_ERR_SIMPLICITY_HIDDEN_ROOT); |
| 3155 | + case SIMPLICITY_ERR_AMR: return set_error(serror, SCRIPT_ERR_SIMPLICITY_AMR); |
| 3156 | + default: return set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); |
| 3157 | + } |
| 3158 | +} |
| 3159 | + |
3041 | 3160 | // explicit instantiation
|
3042 | 3161 | template class GenericTransactionSignatureChecker<CTransaction>;
|
3043 | 3162 | template class GenericTransactionSignatureChecker<CMutableTransaction>;
|
@@ -3186,6 +3305,18 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion,
|
3186 | 3305 | execdata.m_validation_weight_left_init = true;
|
3187 | 3306 | return ExecuteWitnessScript(stack, exec_script, flags, SigVersion::TAPSCRIPT, checker, execdata, serror);
|
3188 | 3307 | }
|
| 3308 | + if ((flags & SCRIPT_VERIFY_SIMPLICITY) && (control[0] & TAPROOT_LEAF_MASK) == TAPROOT_LEAF_TAPSIMPLICITY) { |
| 3309 | + if (stack.size() != 2 || script_bytes.size() != 32) return set_error(serror, SCRIPT_ERR_SIMPLICITY_WRONG_LENGTH); |
| 3310 | + // Tapsimplicity (leaf version 0xbe) |
| 3311 | + const valtype& simplicity_program = SpanPopBack(stack); |
| 3312 | + const valtype& simplicity_witness = SpanPopBack(stack); |
| 3313 | + const int64_t budget = ::GetSerializeSize(witness.stack, PROTOCOL_VERSION) + VALIDATION_WEIGHT_OFFSET; |
| 3314 | + rawTapEnv simplicityRawTap; |
| 3315 | + simplicityRawTap.controlBlock = control.data(); |
| 3316 | + simplicityRawTap.pathLen = (control.size() - TAPROOT_CONTROL_BASE_SIZE) / TAPROOT_CONTROL_NODE_SIZE; |
| 3317 | + simplicityRawTap.scriptCMR = script_bytes.data(); |
| 3318 | + return checker.CheckSimplicity(simplicity_program, simplicity_witness, simplicityRawTap, budget, serror); |
| 3319 | + } |
3189 | 3320 | if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION) {
|
3190 | 3321 | return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION);
|
3191 | 3322 | }
|
|
0 commit comments