diff --git a/configure.ac b/configure.ac index 35bb0c023152..3e9d8d82cca3 100644 --- a/configure.ac +++ b/configure.ac @@ -1622,7 +1622,7 @@ if test x$need_bundled_univalue = xyes; then AC_CONFIG_SUBDIRS([src/univalue]) fi -ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --with-bignum=no --enable-module-recovery --disable-jni" +ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --with-bignum=no --enable-module-recovery --enable-module-schnorrsig --enable-experimental --disable-jni" AC_CONFIG_SUBDIRS([src/secp256k1]) AC_OUTPUT diff --git a/src/chainparams.cpp b/src/chainparams.cpp index ad766471dc13..2d4f7250db1e 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -82,6 +82,11 @@ class CMainParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 + // Deployment of Taproot + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2; + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 + // The best chain should have at least this much work. consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000051dc8b82f450202ecb3d471"); @@ -188,6 +193,11 @@ class CTestNetParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 + // Deployment of Taproot + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2; + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 + // The best chain should have at least this much work. consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000007dbe94253893cbd463"); @@ -271,6 +281,9 @@ class CRegTestParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2; + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE; + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; // The best chain should have at least this much work. consensus.nMinimumChainWork = uint256S("0x00"); diff --git a/src/consensus/params.h b/src/consensus/params.h index 8263b0fef4a8..5aac8351b40b 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -16,6 +16,7 @@ namespace Consensus { enum DeploymentPos { DEPLOYMENT_TESTDUMMY, + DEPLOYMENT_TAPROOT, // Deployment of bip-taproot/bip-tapscript/bip-schnorr // NOTE: Also add new deployments to VersionBitsDeploymentInfo in versionbits.cpp MAX_VERSION_BITS_DEPLOYMENTS }; diff --git a/src/hash.h b/src/hash.h index c295568a3e73..2b2b689a907c 100644 --- a/src/hash.h +++ b/src/hash.h @@ -117,7 +117,7 @@ inline uint160 Hash160(const prevector& vch) class CHashWriter { private: - CHash256 ctx; + CSHA256 ctx; const int nType; const int nVersion; @@ -135,7 +135,16 @@ class CHashWriter // invalidates the object uint256 GetHash() { uint256 result; - ctx.Finalize((unsigned char*)&result); + unsigned char buf[CSHA256::OUTPUT_SIZE]; + ctx.Finalize(buf); + ctx.Reset().Write(buf, CSHA256::OUTPUT_SIZE).Finalize(result.begin()); + return result; + } + + // invalidates the object + uint256 GetSHA256() { + uint256 result; + ctx.Finalize(result.begin()); return result; } @@ -143,9 +152,8 @@ class CHashWriter * Returns the first 64 bits from the resulting hash. */ inline uint64_t GetCheapHash() { - unsigned char result[CHash256::OUTPUT_SIZE]; - ctx.Finalize(result); - return ReadLE64(result); + uint256 result = GetHash(); + return ReadLE64(result.begin()); } template diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index 51de5841ec73..80bf3a20cc86 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -219,16 +219,27 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) if (!prevScript.IsWitnessProgram(witnessversion, witnessprogram)) return false; - // Check P2WSH standard limits - if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) { - if (tx.vin[i].scriptWitness.stack.back().size() > MAX_STANDARD_P2WSH_SCRIPT_SIZE) - return false; - size_t sizeWitnessStack = tx.vin[i].scriptWitness.stack.size() - 1; - if (sizeWitnessStack > MAX_STANDARD_P2WSH_STACK_ITEMS) - return false; - for (unsigned int j = 0; j < sizeWitnessStack; j++) { - if (tx.vin[i].scriptWitness.stack[j].size() > MAX_STANDARD_P2WSH_STACK_ITEM_SIZE) - return false; + auto stack = tx.vin[i].scriptWitness.stack; + if (stack.size() >= 2 && !stack.back().empty() && stack.back()[0] == ANNEX_TAG) { + return false; // annex is non-standard + } + + bool p2wsh = (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE); + bool taproot = (witnessversion == 1 && witnessprogram.size() == WITNESS_V1_TAPROOT_SIZE && (witnessprogram[0] & 0xfe) == 0); + + // Preprocessing for TAPROOT + if (taproot) { + if (stack.size() <= 1) return true; + stack.pop_back(); + } + + // Check P2WSH and TAPROOT standard limits + if (p2wsh || taproot) { + if (stack.back().size() > MAX_STANDARD_WITNESS_SCRIPT_SIZE) return false; + stack.pop_back(); + if (stack.size() > MAX_STANDARD_WITNESS_INPUT_STACK_ITEMS) return false; + for (const auto& item : stack) { + if (item.size() > MAX_STANDARD_WITNESS_INPUT_STACK_ITEM_SIZE) return false; } } } diff --git a/src/policy/policy.h b/src/policy/policy.h index ebe040f0ea7c..eb45c039cfb5 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -36,12 +36,12 @@ static const unsigned int DEFAULT_INCREMENTAL_RELAY_FEE = 1000; static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20; /** Default for -permitbaremultisig */ static const bool DEFAULT_PERMIT_BAREMULTISIG = true; -/** The maximum number of witness stack items in a standard P2WSH script */ -static const unsigned int MAX_STANDARD_P2WSH_STACK_ITEMS = 100; -/** The maximum size of each witness stack item in a standard P2WSH script */ -static const unsigned int MAX_STANDARD_P2WSH_STACK_ITEM_SIZE = 80; -/** The maximum size of a standard witnessScript */ -static const unsigned int MAX_STANDARD_P2WSH_SCRIPT_SIZE = 3600; +/** The maximum number of witness input stack items in a standard witness script */ +static const unsigned int MAX_STANDARD_WITNESS_INPUT_STACK_ITEMS = 210; +/** The maximum size of each witness stack item in a standard witness script */ +static const unsigned int MAX_STANDARD_WITNESS_INPUT_STACK_ITEM_SIZE = 80; +/** The maximum size of a standard witness script */ +static const unsigned int MAX_STANDARD_WITNESS_SCRIPT_SIZE = 7100; /** Min feerate for defining dust. Historically this has been based on the * minRelayTxFee, however changing the dust limit changes which transactions are * standard and should be done with care and ideally rarely. It makes sense to @@ -68,7 +68,12 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VE SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE | - SCRIPT_VERIFY_CONST_SCRIPTCODE; + SCRIPT_VERIFY_CONST_SCRIPTCODE | + SCRIPT_VERIFY_TAPROOT | + SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION | + SCRIPT_VERIFY_DISCOURAGE_UNKNOWN_ANNEX | + SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS | + SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE; /** For convenience, standard but not mandatory verify flags. */ static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS; diff --git a/src/pubkey.cpp b/src/pubkey.cpp index d38df716bd56..5bb0d1a527e1 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -7,6 +7,7 @@ #include #include +#include namespace { @@ -166,6 +167,17 @@ static int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1 return 1; } +bool CPubKey::VerifySchnorr(const uint256 &hash, const std::vector& sigbytes) const { + if (!IsValid()) return false; + if (vch[0] != 2 && vch[0] != 3) return false; // Only compressed pubkeys + if (sigbytes.size() != 64) return false; + secp256k1_pubkey pubkey; + secp256k1_schnorrsig sig; + if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, vch, size())) return false; + if (!secp256k1_schnorrsig_parse(secp256k1_context_verify, &sig, sigbytes.data())) return false; + return secp256k1_schnorrsig_verify(secp256k1_context_verify, &sig, hash.begin(), &pubkey); +} + bool CPubKey::Verify(const uint256 &hash, const std::vector& vchSig) const { if (!IsValid()) return false; @@ -271,6 +283,18 @@ bool CExtPubKey::Derive(CExtPubKey &out, unsigned int _nChild) const { return pubkey.Derive(out.pubkey, out.chaincode, _nChild, chaincode); } +bool CPubKey::CheckPayToContract(const CPubKey& base, const uint256& hash) const +{ + if (!IsCompressed() || !base.IsCompressed()) return false; + secp256k1_pubkey base_point; + if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &base_point, base.vch, base.size())) return false; + if (!secp256k1_ec_pubkey_tweak_add(secp256k1_context_verify, &base_point, hash.begin())) return false; + unsigned char out[COMPRESSED_PUBLIC_KEY_SIZE]; + size_t len = COMPRESSED_PUBLIC_KEY_SIZE; + secp256k1_ec_pubkey_serialize(secp256k1_context_verify, out, &len, &base_point, SECP256K1_EC_COMPRESSED); + return memcmp(out, vch, COMPRESSED_PUBLIC_KEY_SIZE) == 0; +} + /* static */ bool CPubKey::CheckLowS(const std::vector& vchSig) { secp256k1_ecdsa_signature sig; if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, vchSig.data(), vchSig.size())) { diff --git a/src/pubkey.h b/src/pubkey.h index 089324ffda8a..d102e5be8ec7 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -188,6 +188,11 @@ class CPubKey */ bool Verify(const uint256& hash, const std::vector& vchSig) const; + /** + * Verify a Schnorr (DLS) signature (64 bytes) + */ + bool VerifySchnorr(const uint256& hash, const std::vector& sig) const; + /** * Check whether a signature is normalized (lower-S). */ @@ -201,6 +206,9 @@ class CPubKey //! Derive BIP32 child pubkey. bool Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const; + + //! Verify a P2C derivation. Hash must be a cryptographic hash that commits to base. + bool CheckPayToContract(const CPubKey& base, const uint256& hash) const; }; struct CExtPubKey { diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index f8701b6d01a6..1e5558d7c838 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -278,7 +278,7 @@ int FindAndDelete(CScript& script, const CScript& b) return nFound; } -bool EvalScript(std::vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror) +bool EvalScript(std::vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, ScriptExecutionData execdata) { static const CScriptNum bnZero(0); static const CScriptNum bnOne(1); @@ -300,6 +300,9 @@ bool EvalScript(std::vector >& stack, const CScript& return set_error(serror, SCRIPT_ERR_SCRIPT_SIZE); int nOpCount = 0; bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0; + uint32_t sigops_passed = 0; + uint16_t opcode_pos = 0; + execdata.m_codeseparator_pos = 0xFFFF; try { @@ -475,7 +478,7 @@ bool EvalScript(std::vector >& stack, const CScript& if (stack.size() < 1) return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); valtype& vch = stacktop(-1); - if (sigversion == SigVersion::WITNESS_V0 && (flags & SCRIPT_VERIFY_MINIMALIF)) { + if (sigversion == SigVersion::TAPSCRIPT || (sigversion == SigVersion::WITNESS_V0 && (flags & SCRIPT_VERIFY_MINIMALIF))) { if (vch.size() > 1) return set_error(serror, SCRIPT_ERR_MINIMALIF); if (vch.size() == 1 && vch[0] != 1) @@ -908,54 +911,105 @@ bool EvalScript(std::vector >& stack, const CScript& // Hash starts after the code separator pbegincodehash = pc; + execdata.m_codeseparator_pos = opcode_pos; } break; case OP_CHECKSIG: case OP_CHECKSIGVERIFY: + case OP_CHECKSIGADD: { + if (opcode == OP_CHECKSIGADD && sigversion <= SigVersion::WITNESS_V0) { + return set_error(serror, SCRIPT_ERR_BAD_OPCODE); + } + const int args = (opcode == OP_CHECKSIGADD) ? 3 : 2; + // (sig pubkey -- bool) - if (stack.size() < 2) + if (stack.size() < (size_t)args) return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - valtype& vchSig = stacktop(-2); - valtype& vchPubKey = stacktop(-1); + const valtype& vchSig = stacktop(-args); + const valtype& vchPubKey = stacktop(-1); + const CScriptNum num = (opcode == OP_CHECKSIGADD) ? CScriptNum(stacktop(-2), fRequireMinimal) : bnZero; - // Subset of script starting at the most recent codeseparator - CScript scriptCode(pbegincodehash, pend); + bool fSuccess; - // Drop the signature in pre-segwit scripts but not segwit scripts - if (sigversion == SigVersion::BASE) { - int found = FindAndDelete(scriptCode, CScript() << vchSig); - if (found > 0 && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE)) - return set_error(serror, SCRIPT_ERR_SIG_FINDANDDELETE); - } + switch (sigversion) + { + case SigVersion::BASE: + case SigVersion::WITNESS_V0: + { + // Subset of script starting at the most recent codeseparator + execdata.m_scriptcode = CScript(pbegincodehash, pend); - if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, sigversion, serror)) { - //serror is set - return false; - } - bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion); + // Drop the signature in pre-segwit scripts but not segwit scripts + if (sigversion == SigVersion::BASE) { + int found = FindAndDelete(execdata.m_scriptcode, CScript() << vchSig); + if (found > 0 && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE)) + return set_error(serror, SCRIPT_ERR_SIG_FINDANDDELETE); + } - if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && vchSig.size()) - return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL); + if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, sigversion, serror)) { + //serror is set + return false; + } + fSuccess = checker.CheckSig(vchSig, vchPubKey, execdata, sigversion); - popstack(stack); - popstack(stack); - stack.push_back(fSuccess ? vchTrue : vchFalse); - if (opcode == OP_CHECKSIGVERIFY) + if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && vchSig.size()) + return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL); + } + break; + + case SigVersion::TAPSCRIPT: { - if (fSuccess) - popstack(stack); - else - return set_error(serror, SCRIPT_ERR_CHECKSIGVERIFY); + /* + * The following validation sequence is consensus critical. Please note how -- + * upgradable public key versions precede other rules; + * the script execution fails when using empty signature with invalid public key; + * the script execution fails when using non-empty invalid signature. + */ + fSuccess = !vchSig.empty(); + if (vchPubKey.empty() || vchPubKey[0] == 4 || vchPubKey[0] == 6 || vchPubKey[0] == 7) { + return set_error(serror, SCRIPT_ERR_WITNESS_PUBKEYTYPE); + } else if (vchPubKey[0] == 2 || vchPubKey[0] == 3) { + if (!IsCompressedPubKey(vchPubKey)) return set_error(serror, SCRIPT_ERR_WITNESS_PUBKEYTYPE); + if (fSuccess && !checker.CheckSig(vchSig, vchPubKey, execdata, sigversion)) { + return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL); + } + } else { + /* + * New public key version softforks should be defined before this `else` block. + * Generally, the new code should not do anything but failing the script execution. To avoid + * consensus bugs, it must not alter any existing values (including fSuccess and sigops_passed). + */ + if ((flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE) != 0) { + return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_PUBKEYTYPE); + } + } + // Note how the first passing signature is not counted. + // Passing with upgradable public key version is also counted. + assert(execdata.m_witness_weight_init); + if (fSuccess && (sigops_passed++ * VALIDATION_WEIGHT_PER_SIGOP_PASSED > execdata.m_witness_weight)) { + return set_error(serror, SCRIPT_ERR_TAPSCRIPT_VALIDATION_WEIGHT); + } } + break; + + default: assert(false); + } + + for (int i = 0; i < args; ++i) popstack(stack); + if (opcode == OP_CHECKSIGVERIFY && !fSuccess) return set_error(serror, SCRIPT_ERR_CHECKSIGVERIFY); + if (opcode == OP_CHECKSIG) stack.push_back(fSuccess ? vchTrue : vchFalse); + if (opcode == OP_CHECKSIGADD) stack.push_back((num + (fSuccess ? 1 : 0)).getvch()); } break; case OP_CHECKMULTISIG: case OP_CHECKMULTISIGVERIFY: { + if (sigversion == SigVersion::TAPSCRIPT) return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); + // ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool) int i = 1; @@ -985,14 +1039,14 @@ bool EvalScript(std::vector >& stack, const CScript& return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); // Subset of script starting at the most recent codeseparator - CScript scriptCode(pbegincodehash, pend); + execdata.m_scriptcode = CScript(pbegincodehash, pend); // Drop the signature in pre-segwit scripts but not segwit scripts for (int k = 0; k < nSigsCount; k++) { valtype& vchSig = stacktop(-isig-k); if (sigversion == SigVersion::BASE) { - int found = FindAndDelete(scriptCode, CScript() << vchSig); + int found = FindAndDelete(execdata.m_scriptcode, CScript() << vchSig); if (found > 0 && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE)) return set_error(serror, SCRIPT_ERR_SIG_FINDANDDELETE); } @@ -1013,7 +1067,7 @@ bool EvalScript(std::vector >& stack, const CScript& } // Check signature - bool fOk = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion); + bool fOk = checker.CheckSig(vchSig, vchPubKey, execdata, sigversion); if (fOk) { isig++; @@ -1070,6 +1124,8 @@ bool EvalScript(std::vector >& stack, const CScript& // Size limits if (stack.size() + altstack.size() > MAX_STACK_SIZE) return set_error(serror, SCRIPT_ERR_STACK_SIZE); + + ++opcode_pos; } } catch (...) @@ -1189,7 +1245,14 @@ uint256 GetPrevoutHash(const T& txTo) for (const auto& txin : txTo.vin) { ss << txin.prevout; } - return ss.GetHash(); + return ss.GetSHA256(); +} + +uint256 HashAgain(const uint256& hash) +{ + uint256 result; + CSHA256().Write(hash.begin(), 32).Finalize(result.begin()); + return result; } template @@ -1199,7 +1262,7 @@ uint256 GetSequenceHash(const T& txTo) for (const auto& txin : txTo.vin) { ss << txin.nSequence; } - return ss.GetHash(); + return ss.GetSHA256(); } template @@ -1209,27 +1272,146 @@ uint256 GetOutputsHash(const T& txTo) for (const auto& txout : txTo.vout) { ss << txout; } - return ss.GetHash(); + return ss.GetSHA256(); +} + +uint256 GetSpentAmountsHash(const std::vector& outputs_spent) +{ + CHashWriter ss(SER_GETHASH, 0); + for (const auto& txout : outputs_spent) { + ss << txout.nValue; + } + return ss.GetSHA256(); } } // namespace template -PrecomputedTransactionData::PrecomputedTransactionData(const T& txTo) +void PrecomputedTransactionData::Init(const T& txTo, std::vector spent_outputs) { + m_spent_outputs = std::move(spent_outputs); + + if (ready) return; // Cache is calculated only for transactions with witness if (txTo.HasWitness()) { - hashPrevouts = GetPrevoutHash(txTo); - hashSequence = GetSequenceHash(txTo); - hashOutputs = GetOutputsHash(txTo); + m_prevouts_hash = GetPrevoutHash(txTo); + hashPrevouts = HashAgain(m_prevouts_hash); + m_sequences_hash = GetSequenceHash(txTo); + hashSequence = HashAgain(m_sequences_hash); + m_outputs_hash = GetOutputsHash(txTo); + hashOutputs = HashAgain(m_outputs_hash); ready = true; + + if (!m_spent_outputs.empty()) { + m_amounts_spent_hash = GetSpentAmountsHash(m_spent_outputs); + m_amounts_spent_ready = true; + } } } +template +PrecomputedTransactionData::PrecomputedTransactionData(const T& txTo) +{ + Init(txTo, {}); +} + // explicit instantiation +template void PrecomputedTransactionData::Init(const CTransaction& txTo, std::vector spent_outputs); +template void PrecomputedTransactionData::Init(const CMutableTransaction& txTo, std::vector spent_outputs); template PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo); template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo); +CHashWriter TaggedHash(const std::string& tag) +{ + CHashWriter writer(SER_GETHASH, 0); + uint256 taghash; + CSHA256().Write((unsigned char*)tag.data(), tag.size()).Finalize(taghash.begin()); + writer << taghash << taghash; + return writer; +} + +static const CHashWriter HasherTapSighash = TaggedHash("TapSighash"); +static const CHashWriter HasherTapLeaf = TaggedHash("TapLeaf"); +static const CHashWriter HasherTapBranch = TaggedHash("TapBranch"); +static const CHashWriter HasherTapTweak = TaggedHash("TapTweak"); + +template +bool SignatureHashTap(uint256& hash_out, const ScriptExecutionData& execdata, const T& tx_to, const unsigned int in_pos, const uint8_t hash_type, const SigVersion sigversion, const PrecomputedTransactionData& cache) +{ + assert(in_pos < tx_to.vin.size()); + assert(sigversion == SigVersion::TAPROOT || sigversion == SigVersion::TAPSCRIPT); + assert(cache.ready && cache.m_amounts_spent_ready); + + CHashWriter ss = HasherTapSighash; + + // Epoch + uint8_t epoch = 0; + ss << epoch; + + // Hash type + if ((hash_type > 3) && (hash_type < 0x81 || hash_type > 0x83)) return false; + ss << hash_type; + const uint8_t input_type = hash_type & SIGHASH_TAPINPUTMASK; + const uint8_t output_type = hash_type & SIGHASH_TAPOUTPUTMASK; + + // Transaction level data + ss << tx_to.nVersion; + ss << tx_to.nLockTime; + + if (input_type == SIGHASH_TAPDEFAULT) { + ss << cache.m_prevouts_hash; + ss << cache.m_amounts_spent_hash; + ss << cache.m_sequences_hash; + } + if (output_type == SIGHASH_TAPDEFAULT || output_type == SIGHASH_ALL) { + ss << cache.m_outputs_hash; + } + + // Data about the input/prevout being spent + const CScript& scriptPubKey = cache.m_spent_outputs[in_pos].scriptPubKey; + uint8_t spend_type = scriptPubKey.IsPayToScriptHash() ? 1 : 0; + assert(execdata.m_annex_init); + if (execdata.m_annex_present) { + spend_type |= 2; + } + if (sigversion == SigVersion::TAPSCRIPT) { + spend_type |= 4; + } + + ss << spend_type; + ss << scriptPubKey; + + if (input_type == SIGHASH_ANYONECANPAY) { + ss << tx_to.vin[in_pos].prevout; + ss << cache.m_spent_outputs[in_pos].nValue; + ss << tx_to.vin[in_pos].nSequence; + } else { + ss << uint16_t(in_pos); + } + if (execdata.m_annex_present) { + ss << execdata.m_annex_hash; + } + + // Data about the output(s) + if (output_type == SIGHASH_SINGLE) { + if (in_pos >= tx_to.vout.size()) return false; + CHashWriter sha_single_output(SER_GETHASH, 0); + sha_single_output << tx_to.vout[in_pos]; + ss << sha_single_output.GetSHA256(); + } + + // Additional data for tapscript + if (sigversion == SigVersion::TAPSCRIPT) { + assert(execdata.m_tapleaf_hash_init); + ss << execdata.m_tapleaf_hash; + ss << uint8_t(2); // key_version + ss << execdata.m_codeseparator_pos; + } + + hash_out = ss.GetSHA256(); + return true; +} + template uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache) { @@ -1242,16 +1424,16 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn const bool cacheready = cache && cache->ready; if (!(nHashType & SIGHASH_ANYONECANPAY)) { - hashPrevouts = cacheready ? cache->hashPrevouts : GetPrevoutHash(txTo); + hashPrevouts = cacheready ? cache->hashPrevouts : HashAgain(GetPrevoutHash(txTo)); } if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) { - hashSequence = cacheready ? cache->hashSequence : GetSequenceHash(txTo); + hashSequence = cacheready ? cache->hashSequence : HashAgain(GetSequenceHash(txTo)); } if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) { - hashOutputs = cacheready ? cache->hashOutputs : GetOutputsHash(txTo); + hashOutputs = cacheready ? cache->hashOutputs : HashAgain(GetOutputsHash(txTo)); } else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) { CHashWriter ss(SER_GETHASH, 0); ss << txTo.vout[nIn]; @@ -1301,13 +1483,17 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn } template -bool GenericTransactionSignatureChecker::VerifySignature(const std::vector& vchSig, const CPubKey& pubkey, const uint256& sighash) const +bool GenericTransactionSignatureChecker::VerifySignature(const std::vector& vchSig, const CPubKey& pubkey, const uint256& sighash, SignatureType sigtype) const { - return pubkey.Verify(sighash, vchSig); + switch (sigtype) { + case SignatureType::ECDSA: return pubkey.Verify(sighash, vchSig); + case SignatureType::SCHNORR: return pubkey.VerifySchnorr(sighash, vchSig); + } + assert(false); } template -bool GenericTransactionSignatureChecker::CheckSig(const std::vector& vchSigIn, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const +bool GenericTransactionSignatureChecker::CheckSig(const std::vector& vchSigIn, const std::vector& vchPubKey, const ScriptExecutionData& execdata, SigVersion sigversion) const { CPubKey pubkey(vchPubKey); if (!pubkey.IsValid()) @@ -1317,15 +1503,33 @@ bool GenericTransactionSignatureChecker::CheckSig(const std::vector vchSig(vchSigIn); if (vchSig.empty()) return false; - int nHashType = vchSig.back(); - vchSig.pop_back(); - - uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->txdata); - - if (!VerifySignature(vchSig, pubkey, sighash)) - return false; - - return true; + switch (sigversion) { + case SigVersion::BASE: + case SigVersion::WITNESS_V0: + { + int nHashType = vchSig.back(); + vchSig.pop_back(); + uint256 sighash = SignatureHash(execdata.m_scriptcode, *txTo, nIn, nHashType, amount, sigversion, this->txdata); + return VerifySignature(vchSig, pubkey, sighash, SignatureType::ECDSA); + } + case SigVersion::TAPROOT: + case SigVersion::TAPSCRIPT: + { + uint8_t hashtype = SIGHASH_TAPDEFAULT; + if (vchSig.size() == 65) { + hashtype = vchSig.back(); + if (hashtype == SIGHASH_TAPDEFAULT) return false; + vchSig.pop_back(); + } + if (vchSig.size() != 64) return false; + uint256 sighash; + bool ret = SignatureHashTap(sighash, execdata, *txTo, nIn, hashtype, sigversion, *this->txdata); + if (!ret) return false; + return VerifySignature(vchSig, pubkey, sighash, SignatureType::SCHNORR); + } + default: + assert(false); + } } template @@ -1420,8 +1624,11 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, { std::vector > stack; CScript scriptPubKey; + SigVersion sigversion; + ScriptExecutionData execdata; if (witversion == 0) { + sigversion = SigVersion::WITNESS_V0; if (program.size() == WITNESS_V0_SCRIPTHASH_SIZE) { // Version 0 segregated witness program: SHA256(CScript) inside the program, CScript + inputs in witness if (witness.stack.size() == 0) { @@ -1444,6 +1651,79 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, } else { return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH); } + } else if ((flags & SCRIPT_VERIFY_TAPROOT) && witversion == 1 && program.size() == 33 && (program[0] & 0xfe) == 0) { + std::vector pubkey = program; + pubkey[0] = 2 + (pubkey[0] & 1); + stack = witness.stack; + if (stack.size() == 0) return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY); + if (stack.size() >= 2 && !stack.back().empty() && stack.back()[0] == ANNEX_TAG) { + // Drop annex + if (flags & SCRIPT_VERIFY_DISCOURAGE_UNKNOWN_ANNEX) return set_error(serror, SCRIPT_ERR_DISCOURAGE_UNKNOWN_ANNEX); + execdata.m_annex_hash = (CHashWriter(SER_GETHASH, 0) << stack.back()).GetSHA256(); + execdata.m_annex_present = true; + stack.pop_back(); + } else { + execdata.m_annex_present = false; + } + execdata.m_annex_init = true; + if (stack.size() == 1) { + // Key path spending + if (!checker.CheckSig(stack[0], pubkey, execdata, SigVersion::TAPROOT)) { + return set_error(serror, SCRIPT_ERR_TAPROOT_INVALID_SIG); + } + return set_success(serror); + } + // Script path spending + auto control = std::move(stack.back()); + stack.pop_back(); + scriptPubKey = CScript(stack.back().begin(), stack.back().end()); + stack.pop_back(); + if (control.size() < 33 || control.size() > 33 + 32*32 || (control.size() % 32) != 1) { + return set_error(serror, SCRIPT_ERR_TAPROOT_WRONG_CONTROL_SIZE); + } + int path_len = (control.size() - 33) / 32; + std::vector basekey(control.begin(), control.begin() + 33); + basekey[0] = 2 + (basekey[0] & 1); + uint256 k = (CHashWriter(HasherTapLeaf) << uint8_t(control[0] & 0xfe) << scriptPubKey).GetSHA256(); + execdata.m_tapleaf_hash = k; + execdata.m_tapleaf_hash_init = true; + for (int i = 0; i < path_len; ++i) { + CHashWriter ss_branch = HasherTapBranch; + if (std::lexicographical_compare(k.begin(), k.end(), control.begin() + 33 + 32*i, control.begin() + 65 + 32*i)) { + ss_branch << k << Span(control.data() + 33 + 32*i, 32); + } else { + ss_branch << Span(control.data() + 33 + 32*i, 32) << k; + } + k = ss_branch.GetSHA256(); + } + k = (CHashWriter(HasherTapTweak) << MakeSpan(basekey) << k).GetSHA256(); + CPubKey p(basekey.begin(), basekey.end()); + CPubKey q(pubkey.begin(), pubkey.end()); + if (!q.CheckPayToContract(p, k)) return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); + if ((control[0] & 0xfe) == 0xc0) { + sigversion = SigVersion::TAPSCRIPT; + CScript::const_iterator pc = scriptPubKey.begin(); + while (pc < scriptPubKey.end()) { + opcodetype opcode; + if (!scriptPubKey.GetOp(pc, opcode)) { + // Note how this condition would not be reached if an unknown OP_SUCCESSx was found + return set_error(serror, SCRIPT_ERR_BAD_OPCODE); + } + // New opcodes will be listed here. May use a different sigversion to modify existing opcodes. + if (IsOpSuccess(opcode)) { + if (flags & SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS) { + return set_error(serror, SCRIPT_ERR_DISCOURAGE_OP_SUCCESS); + } + return set_success(serror); + } + } + execdata.m_witness_weight = ::GetSerializeSize(witness.stack, PROTOCOL_VERSION); + execdata.m_witness_weight_init = true; + } else if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION) { + return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION); + } else { + return set_success(serror); + } } else if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) { return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM); } else { @@ -1457,7 +1737,7 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, return set_error(serror, SCRIPT_ERR_PUSH_SIZE); } - if (!EvalScript(stack, scriptPubKey, flags, checker, SigVersion::WITNESS_V0, serror)) { + if (!EvalScript(stack, scriptPubKey, flags, checker, sigversion, serror, execdata)) { return false; } diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 276ff9a58a87..d5a464ee60e9 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -16,6 +16,7 @@ class CPubKey; class CScript; class CTransaction; +class CTxOut; class uint256; /** Signature hash types/flags */ @@ -25,6 +26,10 @@ enum SIGHASH_NONE = 2, SIGHASH_SINGLE = 3, SIGHASH_ANYONECANPAY = 0x80, + + SIGHASH_TAPDEFAULT = 0, + SIGHASH_TAPOUTPUTMASK = 3, + SIGHASH_TAPINPUTMASK = 0x80, }; /** Script verification flags. @@ -115,14 +120,41 @@ enum // Making OP_CODESEPARATOR and FindAndDelete fail any non-segwit scripts // SCRIPT_VERIFY_CONST_SCRIPTCODE = (1U << 16), + + // Taproot validation + // + SCRIPT_VERIFY_TAPROOT = (1U << 17), + + // Making unknown taproot inner versions non-standard + SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION = (1U << 18), + + // Making unknown taproot inner versions non-standard + SCRIPT_VERIFY_DISCOURAGE_UNKNOWN_ANNEX = (1U << 19), + + // Making unknown OP_SUCCESS non-standard + SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS = (1U << 20), + + // Making unknown public key versions in tapscript non-standard + SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE = (1U << 21), }; bool CheckSignatureEncoding(const std::vector &vchSig, unsigned int flags, ScriptError* serror); struct PrecomputedTransactionData { + //! Single-SHA256 versions + uint256 m_prevouts_hash, m_sequences_hash, m_outputs_hash, m_amounts_spent_hash; + bool m_amounts_spent_ready = false; + + //! Double-SHA256 versions uint256 hashPrevouts, hashSequence, hashOutputs; bool ready = false; + std::vector m_spent_outputs; + + PrecomputedTransactionData() = default; + + template + void Init(const T& tx, std::vector spent_outputs); template explicit PrecomputedTransactionData(const T& tx); @@ -132,19 +164,41 @@ enum class SigVersion { BASE = 0, WITNESS_V0 = 1, + TAPROOT = 2, + TAPSCRIPT = 3, +}; + +struct ScriptExecutionData +{ + CScript m_scriptcode; + + bool m_tapleaf_hash_init = false; + uint256 m_tapleaf_hash; + uint16_t m_codeseparator_pos; + + bool m_annex_init = false; + bool m_annex_present; + uint256 m_annex_hash; + + bool m_witness_weight_init = false; + size_t m_witness_weight; }; /** Signature hash sizes */ static constexpr size_t WITNESS_V0_SCRIPTHASH_SIZE = 32; static constexpr size_t WITNESS_V0_KEYHASH_SIZE = 20; +static constexpr size_t WITNESS_V1_TAPROOT_SIZE = 33; template uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr); +template +bool SignatureHashTap(uint256& hash_out, const ScriptExecutionData& execdata, const T& tx_to, unsigned int in_pos, uint8_t hash_type, SigVersion sigversion, const PrecomputedTransactionData& cache); + class BaseSignatureChecker { public: - virtual bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const + virtual bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const ScriptExecutionData& execdata, SigVersion sigversion) const { return false; } @@ -162,6 +216,11 @@ class BaseSignatureChecker virtual ~BaseSignatureChecker() {} }; +enum class SignatureType { + ECDSA, + SCHNORR +}; + template class GenericTransactionSignatureChecker : public BaseSignatureChecker { @@ -172,12 +231,12 @@ class GenericTransactionSignatureChecker : public BaseSignatureChecker const PrecomputedTransactionData* txdata; protected: - virtual bool VerifySignature(const std::vector& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; + virtual bool VerifySignature(const std::vector& vchSig, const CPubKey& vchPubKey, const uint256& sighash, SignatureType sigtype) const; public: GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(nullptr) {} GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {} - bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override; + bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const ScriptExecutionData& execdata, SigVersion sigversion) const override; bool CheckLockTime(const CScriptNum& nLockTime) const override; bool CheckSequence(const CScriptNum& nSequence) const override; }; @@ -185,7 +244,7 @@ class GenericTransactionSignatureChecker : public BaseSignatureChecker using TransactionSignatureChecker = GenericTransactionSignatureChecker; using MutableTransactionSignatureChecker = GenericTransactionSignatureChecker; -bool EvalScript(std::vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr); +bool EvalScript(std::vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr, ScriptExecutionData execdata = {}); bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror = nullptr); size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags); diff --git a/src/script/script.cpp b/src/script/script.cpp index 0666a385d1be..2e59bcb30d43 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -138,6 +138,9 @@ const char* GetOpName(opcodetype opcode) case OP_NOP9 : return "OP_NOP9"; case OP_NOP10 : return "OP_NOP10"; + // taproot + case OP_CHECKSIGADD : return "OP_CHECKSIGADD"; + case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE"; default: @@ -326,3 +329,11 @@ bool GetScriptOp(CScriptBase::const_iterator& pc, CScriptBase::const_iterator en opcodeRet = static_cast(opcode); return true; } + +bool IsOpSuccess(const opcodetype& opcode) +{ + return (opcode == 0x50 || opcode == 0x62 || opcode == 0x89 || + opcode == 0x8a || opcode == 0x8d || opcode == 0x8e || + (opcode >= 0x7e && opcode <= 0x81) || (opcode >= 0x83 && opcode <= 0x86) || + (opcode >= 0x95 && opcode <= 0x99) || (opcode >= 0xbb && opcode <= 0xfe)); +} \ No newline at end of file diff --git a/src/script/script.h b/src/script/script.h index 6355b8a704e1..b7a2bf1526c4 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -44,6 +44,15 @@ static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 // SEQUENCE_FINAL). static const uint32_t LOCKTIME_MAX = 0xFFFFFFFFU; +// Tag for input annex. If there are at least two witness elements for a transaction input, +// and the first byte of the last element is 0x50, this last element is called annex, and +// has meanings independent of the script +static const unsigned int ANNEX_TAG = 0x50; + +// Validation weight per passing signature (tapscript only) +// The first passing signature is not counted +static const size_t VALIDATION_WEIGHT_PER_SIGOP_PASSED = 50; + template std::vector ToByteVector(const T& in) { @@ -187,6 +196,9 @@ enum opcodetype OP_NOP9 = 0xb8, OP_NOP10 = 0xb9, + // taproot + OP_CHECKSIGADD = 0xba, + OP_INVALIDOPCODE = 0xff, }; @@ -583,4 +595,6 @@ struct CScriptWitness std::string ToString() const; }; +bool IsOpSuccess(const opcodetype& opcode); + #endif // BITCOIN_SCRIPT_SCRIPT_H diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp index 9d7deffc783a..865b49cf6cbf 100644 --- a/src/script/script_error.cpp +++ b/src/script/script_error.cpp @@ -71,6 +71,14 @@ const char* ScriptErrorString(const ScriptError serror) return "NOPx reserved for soft-fork upgrades"; case SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM: return "Witness version reserved for soft-fork upgrades"; + case SCRIPT_ERR_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION: + return "Taproot version reserved for soft-fork upgrades"; + case SCRIPT_ERR_DISCOURAGE_UNKNOWN_ANNEX: + return "Unknown input annex reserved for soft-fork upgrades"; + case SCRIPT_ERR_DISCOURAGE_OP_SUCCESS: + return "SUCCESSx reserved for soft-fork upgrades"; + case SCRIPT_ERR_DISCOURAGE_UPGRADABLE_PUBKEYTYPE: + return "Public key version reserved for soft-fork upgrades"; case SCRIPT_ERR_PUBKEYTYPE: return "Public key is neither compressed or uncompressed"; case SCRIPT_ERR_CLEANSTACK: @@ -89,6 +97,12 @@ const char* ScriptErrorString(const ScriptError serror) return "Witness provided for non-witness script"; case SCRIPT_ERR_WITNESS_PUBKEYTYPE: return "Using non-compressed keys in segwit"; + case SCRIPT_ERR_TAPROOT_INVALID_SIG: + return "Invalid signature for taproot key path spending"; + case SCRIPT_ERR_TAPROOT_WRONG_CONTROL_SIZE: + return "Invalid taproot control block size"; + case SCRIPT_ERR_TAPSCRIPT_VALIDATION_WEIGHT: + return "Too much signature validation relative to witness weight"; case SCRIPT_ERR_OP_CODESEPARATOR: return "Using OP_CODESEPARATOR in non-witness script"; case SCRIPT_ERR_SIG_FINDANDDELETE: diff --git a/src/script/script_error.h b/src/script/script_error.h index 400f63ff0f7f..fb9832797e90 100644 --- a/src/script/script_error.h +++ b/src/script/script_error.h @@ -54,6 +54,10 @@ typedef enum ScriptError_t /* softfork safeness */ SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM, + SCRIPT_ERR_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION, + SCRIPT_ERR_DISCOURAGE_UNKNOWN_ANNEX, + SCRIPT_ERR_DISCOURAGE_OP_SUCCESS, + SCRIPT_ERR_DISCOURAGE_UPGRADABLE_PUBKEYTYPE, /* segregated witness */ SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH, @@ -64,6 +68,11 @@ typedef enum ScriptError_t SCRIPT_ERR_WITNESS_UNEXPECTED, SCRIPT_ERR_WITNESS_PUBKEYTYPE, + /* Taproot */ + SCRIPT_ERR_TAPROOT_INVALID_SIG, + SCRIPT_ERR_TAPROOT_WRONG_CONTROL_SIZE, + SCRIPT_ERR_TAPSCRIPT_VALIDATION_WEIGHT, + /* Constant scriptCode */ SCRIPT_ERR_OP_CODESEPARATOR, SCRIPT_ERR_SIG_FINDANDDELETE, diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp index eaf5363bd787..684c1b9a2ce5 100644 --- a/src/script/sigcache.cpp +++ b/src/script/sigcache.cpp @@ -35,9 +35,14 @@ class CSignatureCache } void - ComputeEntry(uint256& entry, const uint256 &hash, const std::vector& vchSig, const CPubKey& pubkey) + ComputeEntry(uint256& entry, const uint256 &hash, const std::vector& vchSig, const CPubKey& pubkey, SignatureType sigtype) { - CSHA256().Write(nonce.begin(), 32).Write(hash.begin(), 32).Write(&pubkey[0], pubkey.size()).Write(&vchSig[0], vchSig.size()).Finalize(entry.begin()); + unsigned char st; + switch (sigtype) { + case SignatureType::ECDSA: st = 'E'; break; + case SignatureType::SCHNORR: st = 'S'; break; + } + CSHA256().Write(nonce.begin(), 32).Write(hash.begin(), 32).Write(&pubkey[0], pubkey.size()).Write(&st, 1).Write(&vchSig[0], vchSig.size()).Finalize(entry.begin()); } bool @@ -79,13 +84,13 @@ void InitSignatureCache() (nElems*sizeof(uint256)) >>20, (nMaxCacheSize*2)>>20, nElems); } -bool CachingTransactionSignatureChecker::VerifySignature(const std::vector& vchSig, const CPubKey& pubkey, const uint256& sighash) const +bool CachingTransactionSignatureChecker::VerifySignature(const std::vector& vchSig, const CPubKey& pubkey, const uint256& sighash, SignatureType sigtype) const { uint256 entry; - signatureCache.ComputeEntry(entry, sighash, vchSig, pubkey); + signatureCache.ComputeEntry(entry, sighash, vchSig, pubkey, sigtype); if (signatureCache.Get(entry, !store)) return true; - if (!TransactionSignatureChecker::VerifySignature(vchSig, pubkey, sighash)) + if (!TransactionSignatureChecker::VerifySignature(vchSig, pubkey, sighash, sigtype)) return false; if (store) signatureCache.Set(entry); diff --git a/src/script/sigcache.h b/src/script/sigcache.h index 807b61b542fb..c444f78e6f35 100644 --- a/src/script/sigcache.h +++ b/src/script/sigcache.h @@ -48,7 +48,7 @@ class CachingTransactionSignatureChecker : public TransactionSignatureChecker public: CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amountIn, txdataIn), store(storeIn) {} - bool VerifySignature(const std::vector& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const override; + bool VerifySignature(const std::vector& vchSig, const CPubKey& vchPubKey, const uint256& sighash, SignatureType sigtype) const override; }; void InitSignatureCache(); diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 13481af9c506..99da7dd917f5 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -252,12 +252,12 @@ class SignatureExtractorChecker final : public BaseSignatureChecker public: SignatureExtractorChecker(SignatureData& sigdata, BaseSignatureChecker& checker) : sigdata(sigdata), checker(checker) {} - bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override; + bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const ScriptExecutionData& execdata, SigVersion sigversion) const override; }; -bool SignatureExtractorChecker::CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const +bool SignatureExtractorChecker::CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const ScriptExecutionData& execdata, SigVersion sigversion) const { - if (checker.CheckSig(scriptSig, vchPubKey, scriptCode, sigversion)) { + if (checker.CheckSig(scriptSig, vchPubKey, execdata, sigversion)) { CPubKey pubkey(vchPubKey); sigdata.signatures.emplace(pubkey.GetID(), SigPair(pubkey, scriptSig)); return true; @@ -335,7 +335,9 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI for (unsigned int i = last_success_key; i < num_pubkeys; ++i) { const valtype& pubkey = solutions[i+1]; // We either have a signature for this pubkey, or we have found a signature and it is valid - if (data.signatures.count(CPubKey(pubkey).GetID()) || extractor_checker.CheckSig(sig, pubkey, next_script, sigversion)) { + ScriptExecutionData execdata; + execdata.m_scriptcode = next_script; + if (data.signatures.count(CPubKey(pubkey).GetID()) || extractor_checker.CheckSig(sig, pubkey, execdata, sigversion)) { last_success_key = i + 1; break; } @@ -396,7 +398,7 @@ class DummySignatureChecker final : public BaseSignatureChecker { public: DummySignatureChecker() {} - bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override { return true; } + bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const ScriptExecutionData& execdata, SigVersion sigversion) const override { return true; } }; const DummySignatureChecker DUMMY_CHECKER; diff --git a/src/secp256k1/.gitignore b/src/secp256k1/.gitignore index 55d325aeefa9..905be987305a 100644 --- a/src/secp256k1/.gitignore +++ b/src/secp256k1/.gitignore @@ -1,9 +1,9 @@ bench_inv bench_ecdh bench_ecmult +bench_schnorrsig bench_sign bench_verify -bench_schnorr_verify bench_recover bench_internal tests diff --git a/src/secp256k1/.travis.yml b/src/secp256k1/.travis.yml index 74f658f4d1c6..9e9fd6f214e4 100644 --- a/src/secp256k1/.travis.yml +++ b/src/secp256k1/.travis.yml @@ -11,20 +11,20 @@ cache: - src/java/guava/ env: global: - - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no JNI=no + - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no JNI=no SCHNORRSIG=no - GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar matrix: - SCALAR=32bit RECOVERY=yes - - SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes + - SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes - SCALAR=64bit - - FIELD=64bit RECOVERY=yes + - FIELD=64bit RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes - FIELD=64bit ENDOMORPHISM=yes - - FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes + - FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes - FIELD=64bit ASM=x86_64 - FIELD=64bit ENDOMORPHISM=yes ASM=x86_64 - FIELD=32bit ENDOMORPHISM=yes - BIGNUM=no - - BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes + - BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes - BIGNUM=no STATICPRECOMPUTATION=no - BUILD=distcheck - EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC @@ -65,4 +65,4 @@ before_script: ./autogen.sh script: - if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi - if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi - - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY --enable-jni=$JNI $EXTRAFLAGS $USE_HOST && make -j2 $BUILD + - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY --enable-module-schnorrsig=$SCHNORRSIG --enable-jni=$JNI $EXTRAFLAGS $USE_HOST && make -j2 $BUILD diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am index 9e5b7dcce0ab..1d985c17e130 100644 --- a/src/secp256k1/Makefile.am +++ b/src/secp256k1/Makefile.am @@ -8,6 +8,7 @@ else JNI_LIB = endif include_HEADERS = include/secp256k1.h +include_HEADERS += include/secp256k1_preallocated.h noinst_HEADERS = noinst_HEADERS += src/scalar.h noinst_HEADERS += src/scalar_4x64.h @@ -177,6 +178,10 @@ if ENABLE_MODULE_ECDH include src/modules/ecdh/Makefile.am.include endif +if ENABLE_MODULE_SCHNORRSIG +include src/modules/schnorrsig/Makefile.am.include +endif + if ENABLE_MODULE_RECOVERY include src/modules/recovery/Makefile.am.include endif diff --git a/src/secp256k1/README.md b/src/secp256k1/README.md index 8cd344ea8123..1c66d712d4d6 100644 --- a/src/secp256k1/README.md +++ b/src/secp256k1/README.md @@ -45,8 +45,10 @@ Implementation details * Optionally (off by default) use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones. * Point multiplication for signing * Use a precomputed table of multiples of powers of 16 multiplied with the generator, so general multiplication becomes a series of additions. - * Access the table with branch-free conditional moves so memory access is uniform. - * No data-dependent branches + * Intended to be completely free of timing sidechannels for secret-key operations (on reasonable hardware/toolchains) + * Access the table with branch-free conditional moves so memory access is uniform. + * No data-dependent branches + * Optional runtime blinding which attempts to frustrate differential power analysis. * The precomputed tables add and eventually subtract points for which no known scalar (private key) is known, preventing even an attacker with control over the private key used to control the data internally. Build steps diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac index 3b7a328c8af0..3c21169e3f0b 100644 --- a/src/secp256k1/configure.ac +++ b/src/secp256k1/configure.ac @@ -85,42 +85,42 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], ]) AC_ARG_ENABLE(benchmark, - AS_HELP_STRING([--enable-benchmark],[compile benchmark (default is yes)]), + AS_HELP_STRING([--enable-benchmark],[compile benchmark [default=yes]]), [use_benchmark=$enableval], [use_benchmark=yes]) AC_ARG_ENABLE(coverage, - AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis]), + AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis [default=no]]), [enable_coverage=$enableval], [enable_coverage=no]) AC_ARG_ENABLE(tests, - AS_HELP_STRING([--enable-tests],[compile tests (default is yes)]), + AS_HELP_STRING([--enable-tests],[compile tests [default=yes]]), [use_tests=$enableval], [use_tests=yes]) AC_ARG_ENABLE(openssl_tests, - AS_HELP_STRING([--enable-openssl-tests],[enable OpenSSL tests, if OpenSSL is available (default is auto)]), + AS_HELP_STRING([--enable-openssl-tests],[enable OpenSSL tests [default=auto]]), [enable_openssl_tests=$enableval], [enable_openssl_tests=auto]) AC_ARG_ENABLE(experimental, - AS_HELP_STRING([--enable-experimental],[allow experimental configure options (default is no)]), + AS_HELP_STRING([--enable-experimental],[allow experimental configure options [default=no]]), [use_experimental=$enableval], [use_experimental=no]) AC_ARG_ENABLE(exhaustive_tests, - AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests (default is yes)]), + AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests [default=yes]]), [use_exhaustive_tests=$enableval], [use_exhaustive_tests=yes]) AC_ARG_ENABLE(endomorphism, - AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]), + AS_HELP_STRING([--enable-endomorphism],[enable endomorphism [default=no]]), [use_endomorphism=$enableval], [use_endomorphism=no]) AC_ARG_ENABLE(ecmult_static_precomputation, - AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing (default is yes)]), + AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing [default=auto]]), [use_ecmult_static_precomputation=$enableval], [use_ecmult_static_precomputation=auto]) @@ -129,34 +129,53 @@ AC_ARG_ENABLE(module_ecdh, [enable_module_ecdh=$enableval], [enable_module_ecdh=no]) +AC_ARG_ENABLE(module_schnorrsig, + AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module (experimental)]), + [enable_module_schnorrsig=$enableval], + [enable_module_schnorrsig=no]) + AC_ARG_ENABLE(module_recovery, - AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module (default is no)]), + AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module [default=no]]), [enable_module_recovery=$enableval], [enable_module_recovery=no]) +AC_ARG_ENABLE(external_default_callbacks, + AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions (default is no)]), + [use_external_default_callbacks=$enableval], + [use_external_default_callbacks=no]) + AC_ARG_ENABLE(jni, - AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni (default is no)]), + AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni [default=no]]), [use_jni=$enableval], [use_jni=no]) AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto], -[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto]) +[finite field implementation to use [default=auto]])],[req_field=$withval], [req_field=auto]) AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto], -[Specify Bignum Implementation. Default is auto])],[req_bignum=$withval], [req_bignum=auto]) +[bignum implementation to use [default=auto]])],[req_bignum=$withval], [req_bignum=auto]) AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto], -[Specify scalar implementation. Default is auto])],[req_scalar=$withval], [req_scalar=auto]) +[scalar implementation to use [default=auto]])],[req_scalar=$withval], [req_scalar=auto]) + +AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto], +[assembly optimizations to useĀ (experimental: arm) [default=auto]])],[req_asm=$withval], [req_asm=auto]) -AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto] -[Specify assembly optimizations to use. Default is auto (experimental: arm)])],[req_asm=$withval], [req_asm=auto]) +AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE|auto], +[window size for ecmult precomputation for verification, specified as integer in range [2..24].] +[Larger values result in possibly better performance at the cost of an exponentially larger precomputed table.] +[The table will store 2^(SIZE-2) * 64 bytes of data but can be larger in memory due to platform-specific padding and alignment.] +[If the endomorphism optimization is enabled, two tables of this size are used instead of only one.] +["auto" is a reasonable setting for desktop machines (currently 15). [default=auto]] +)], +[req_ecmult_window=$withval], [req_ecmult_window=auto]) AC_CHECK_TYPES([__int128]) if test x"$enable_coverage" = x"yes"; then AC_DEFINE(COVERAGE, 1, [Define this symbol to compile out all VERIFY code]) CFLAGS="$CFLAGS -O0 --coverage" - LDFLAGS="--coverage" + LDFLAGS="$LDFLAGS --coverage" else CFLAGS="$CFLAGS -O3" fi @@ -387,6 +406,28 @@ case $set_scalar in ;; esac +#set ecmult window size +if test x"$req_ecmult_window" = x"auto"; then + set_ecmult_window=15 +else + set_ecmult_window=$req_ecmult_window +fi + +error_window_size=['window size for ecmult precomputation not an integer in range [2..24] or "auto"'] +case $set_ecmult_window in +''|*[[!0-9]]*) + # no valid integer + AC_MSG_ERROR($error_window_size) + ;; +*) + if test "$set_ecmult_window" -lt 2 -o "$set_ecmult_window" -gt 24 ; then + # not in range + AC_MSG_ERROR($error_window_size) + fi + AC_DEFINE_UNQUOTED(ECMULT_WINDOW_SIZE, $set_ecmult_window, [Set window size for ecmult precomputation]) + ;; +esac + if test x"$use_tests" = x"yes"; then SECP_OPENSSL_CHECK if test x"$has_openssl_ec" = x"yes"; then @@ -452,6 +493,10 @@ if test x"$enable_module_ecdh" = x"yes"; then AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module]) fi +if test x"$enable_module_schnorrsig" = x"yes"; then + AC_DEFINE(ENABLE_MODULE_SCHNORRSIG, 1, [Define this symbol to enable the schnorrsig module]) +fi + if test x"$enable_module_recovery" = x"yes"; then AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module]) fi @@ -462,16 +507,24 @@ if test x"$use_external_asm" = x"yes"; then AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used]) fi +if test x"$use_external_default_callbacks" = x"yes"; then + AC_DEFINE(USE_EXTERNAL_DEFAULT_CALLBACKS, 1, [Define this symbol if an external implementation of the default callbacks is used]) +fi + if test x"$enable_experimental" = x"yes"; then AC_MSG_NOTICE([******]) AC_MSG_NOTICE([WARNING: experimental build]) AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.]) AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh]) + AC_MSG_NOTICE([Building schnorrsig module: $enable_module_schnorrsig]) AC_MSG_NOTICE([******]) else if test x"$enable_module_ecdh" = x"yes"; then AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.]) fi + if test x"$enable_module_schnorrsig" = x"yes"; then + AC_MSG_ERROR([schnorrsig module is experimental. Use --enable-experimental to allow.]) + fi if test x"$set_asm" = x"arm"; then AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.]) fi @@ -490,6 +543,7 @@ AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$use_exhaustive_tests" != x"no"]) AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"]) AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$set_precomp" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"]) AM_CONDITIONAL([USE_JNI], [test x"$use_jni" = x"yes"]) AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"]) @@ -504,21 +558,24 @@ AC_OUTPUT echo echo "Build Options:" -echo " with endomorphism = $use_endomorphism" -echo " with ecmult precomp = $set_precomp" -echo " with jni = $use_jni" -echo " with benchmarks = $use_benchmark" -echo " with coverage = $enable_coverage" -echo " module ecdh = $enable_module_ecdh" -echo " module recovery = $enable_module_recovery" +echo " with endomorphism = $use_endomorphism" +echo " with ecmult precomp = $set_precomp" +echo " with external callbacks = $use_external_default_callbacks" +echo " with jni = $use_jni" +echo " with benchmarks = $use_benchmark" +echo " with coverage = $enable_coverage" +echo " module ecdh = $enable_module_ecdh" +echo " module recovery = $enable_module_recovery" +echo " module schnorrsig = $enable_module_schnorrsig" echo -echo " asm = $set_asm" -echo " bignum = $set_bignum" -echo " field = $set_field" -echo " scalar = $set_scalar" +echo " asm = $set_asm" +echo " bignum = $set_bignum" +echo " field = $set_field" +echo " scalar = $set_scalar" +echo " ecmult window size = $set_ecmult_window" echo -echo " CC = $CC" -echo " CFLAGS = $CFLAGS" -echo " CPPFLAGS = $CPPFLAGS" -echo " LDFLAGS = $LDFLAGS" +echo " CC = $CC" +echo " CFLAGS = $CFLAGS" +echo " CPPFLAGS = $CPPFLAGS" +echo " LDFLAGS = $LDFLAGS" echo diff --git a/src/secp256k1/contrib/lax_der_parsing.c b/src/secp256k1/contrib/lax_der_parsing.c index 5b141a99481c..e177a0562dd2 100644 --- a/src/secp256k1/contrib/lax_der_parsing.c +++ b/src/secp256k1/contrib/lax_der_parsing.c @@ -32,7 +32,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_ lenbyte = input[pos++]; if (lenbyte & 0x80) { lenbyte -= 0x80; - if (pos + lenbyte > inputlen) { + if (lenbyte > inputlen - pos) { return 0; } pos += lenbyte; @@ -51,7 +51,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_ lenbyte = input[pos++]; if (lenbyte & 0x80) { lenbyte -= 0x80; - if (pos + lenbyte > inputlen) { + if (lenbyte > inputlen - pos) { return 0; } while (lenbyte > 0 && input[pos] == 0) { @@ -89,7 +89,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_ lenbyte = input[pos++]; if (lenbyte & 0x80) { lenbyte -= 0x80; - if (pos + lenbyte > inputlen) { + if (lenbyte > inputlen - pos) { return 0; } while (lenbyte > 0 && input[pos] == 0) { diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h index 43af09c330de..5988b14193b5 100644 --- a/src/secp256k1/include/secp256k1.h +++ b/src/secp256k1/include/secp256k1.h @@ -33,9 +33,10 @@ extern "C" { * verification). * * A constructed context can safely be used from multiple threads - * simultaneously, but API call that take a non-const pointer to a context + * simultaneously, but API calls that take a non-const pointer to a context * need exclusive access to it. In particular this is the case for - * secp256k1_context_destroy and secp256k1_context_randomize. + * secp256k1_context_destroy, secp256k1_context_preallocated_destroy, + * and secp256k1_context_randomize. * * Regarding randomization, either do it once at creation time (in which case * you do not need any locking for the other calls), or use a read-write lock. @@ -163,7 +164,8 @@ typedef int (*secp256k1_nonce_function)( #define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9) #define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8) -/** Flags to pass to secp256k1_context_create. */ +/** Flags to pass to secp256k1_context_create, secp256k1_context_preallocated_size, and + * secp256k1_context_preallocated_create. */ #define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) #define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN) #define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT) @@ -186,7 +188,11 @@ typedef int (*secp256k1_nonce_function)( */ SECP256K1_API extern const secp256k1_context *secp256k1_context_no_precomp; -/** Create a secp256k1 context object. +/** Create a secp256k1 context object (in dynamically allocated memory). + * + * This function uses malloc to allocate memory. It is guaranteed that malloc is + * called at most once for every call of this function. If you need to avoid dynamic + * memory allocation entirely, see the functions in secp256k1_preallocated.h. * * Returns: a newly created context object. * In: flags: which parts of the context to initialize. @@ -197,7 +203,11 @@ SECP256K1_API secp256k1_context* secp256k1_context_create( unsigned int flags ) SECP256K1_WARN_UNUSED_RESULT; -/** Copies a secp256k1 context object. +/** Copy a secp256k1 context object (into dynamically allocated memory). + * + * This function uses malloc to allocate memory. It is guaranteed that malloc is + * called at most once for every call of this function. If you need to avoid dynamic + * memory allocation entirely, see the functions in secp256k1_preallocated.h. * * Returns: a newly created context object. * Args: ctx: an existing context to copy (cannot be NULL) @@ -206,10 +216,18 @@ SECP256K1_API secp256k1_context* secp256k1_context_clone( const secp256k1_context* ctx ) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; -/** Destroy a secp256k1 context object. +/** Destroy a secp256k1 context object (created in dynamically allocated memory). * * The context pointer may not be used afterwards. - * Args: ctx: an existing context to destroy (cannot be NULL) + * + * The context to destroy must have been created using secp256k1_context_create + * or secp256k1_context_clone. If the context has instead been created using + * secp256k1_context_preallocated_create or secp256k1_context_preallocated_clone, the + * behaviour is undefined. In that case, secp256k1_context_preallocated_destroy must + * be used instead. + * + * Args: ctx: an existing context to destroy, constructed using + * secp256k1_context_create or secp256k1_context_clone */ SECP256K1_API void secp256k1_context_destroy( secp256k1_context* ctx @@ -229,11 +247,28 @@ SECP256K1_API void secp256k1_context_destroy( * to cause a crash, though its return value and output arguments are * undefined. * + * When this function has not been called (or called with fn==NULL), then the + * default handler will be used.Ā The library provides a default handler which + * writes the message to stderr and calls abort. This default handler can be + * replaced at link time if the preprocessor macro + * USE_EXTERNAL_DEFAULT_CALLBACKS is defined, which is the case if the build + * has been configured with --enable-external-default-callbacks. Then the + * following two symbols must be provided to link against: + * - void secp256k1_default_illegal_callback_fn(const char* message, void* data); + * - void secp256k1_default_error_callback_fn(const char* message, void* data); + * The library can call these default handlers even before a proper callback data + * pointer could have been set using secp256k1_context_set_illegal_callback or + * secp256k1_context_set_illegal_callback, e.g., when the creation of a context + * fails. In this case, the corresponding default handler will be called with + * the data pointer argument set to NULL. + * * Args: ctx: an existing context object (cannot be NULL) * In: fun: a pointer to a function to call when an illegal argument is - * passed to the API, taking a message and an opaque pointer - * (NULL restores a default handler that calls abort). + * passed to the API, taking a message and an opaque pointer. + * (NULL restores the default handler.) * data: the opaque pointer to pass to fun above. + * + * See also secp256k1_context_set_error_callback. */ SECP256K1_API void secp256k1_context_set_illegal_callback( secp256k1_context* ctx, @@ -253,9 +288,12 @@ SECP256K1_API void secp256k1_context_set_illegal_callback( * * Args: ctx: an existing context object (cannot be NULL) * In: fun: a pointer to a function to call when an internal error occurs, - * taking a message and an opaque pointer (NULL restores a default - * handler that calls abort). + * taking a message and an opaque pointer (NULL restores the + * default handler, see secp256k1_context_set_illegal_callback + * for details). * data: the opaque pointer to pass to fun above. + * + * See also secp256k1_context_set_illegal_callback. */ SECP256K1_API void secp256k1_context_set_error_callback( secp256k1_context* ctx, @@ -267,21 +305,24 @@ SECP256K1_API void secp256k1_context_set_error_callback( * * Returns: a newly created scratch space. * Args: ctx: an existing context object (cannot be NULL) - * In: max_size: maximum amount of memory to allocate + * In: size: amount of memory to be available as scratch space. Some extra + * (<100 bytes) will be allocated for extra accounting. */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space* secp256k1_scratch_space_create( const secp256k1_context* ctx, - size_t max_size + size_t size ) SECP256K1_ARG_NONNULL(1); /** Destroy a secp256k1 scratch space. * * The pointer may not be used afterwards. - * Args: scratch: space to destroy + * Args: ctx: a secp256k1 context object. + * scratch: space to destroy */ SECP256K1_API void secp256k1_scratch_space_destroy( + const secp256k1_context* ctx, secp256k1_scratch_space* scratch -); +) SECP256K1_ARG_NONNULL(1); /** Parse a variable-length public key into the pubkey object. * @@ -482,6 +523,12 @@ SECP256K1_API int secp256k1_ecdsa_signature_normalize( */ SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_rfc6979; +/** An implementation of the nonce generation function as defined in BIP-schnorr. + * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of + * extra entropy. + */ +SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_bipschnorr; + /** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */ SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_default; @@ -636,7 +683,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul( * contexts not initialized for signing; then it will have no effect and return 1. * * You should call this after secp256k1_context_create or - * secp256k1_context_clone, and may call this repeatedly afterwards. + * secp256k1_context_clone (and secp256k1_context_preallocated_create or + * secp256k1_context_clone, resp.), and you may call this repeatedly afterwards. */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize( secp256k1_context* ctx, diff --git a/src/secp256k1/include/secp256k1_preallocated.h b/src/secp256k1/include/secp256k1_preallocated.h new file mode 100644 index 000000000000..0fb64a5431f8 --- /dev/null +++ b/src/secp256k1/include/secp256k1_preallocated.h @@ -0,0 +1,128 @@ +#ifndef SECP256K1_PREALLOCATED_H +#define SECP256K1_PREALLOCATED_H + +#include "secp256k1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* The module provided by this header file is intended for settings in which it + * is not possible or desirable to rely on dynamic memory allocation. It provides + * functions for creating, cloning, and destroying secp256k1 context objects in a + * contiguous fixed-size block of memory provided by the caller. + * + * Context objects created by functions in this module can be used like contexts + * objects created by functions in secp256k1.h, i.e., they can be passed to any + * API function that excepts a context object (see secp256k1.h for details). The + * only exception is that context objects created by functions in this module + * must be destroyed using secp256k1_context_preallocated_destroy (in this + * module) instead of secp256k1_context_destroy (in secp256k1.h). + * + * It is guaranteed that functions in by this module will not call malloc or its + * friends realloc, calloc, and free. + */ + +/** Determine the memory size of a secp256k1 context object to be created in + * caller-provided memory. + * + * The purpose of this function is to determine how much memory must be provided + * to secp256k1_context_preallocated_create. + * + * Returns: the required size of the caller-provided memory block + * In: flags: which parts of the context to initialize. + */ +SECP256K1_API size_t secp256k1_context_preallocated_size( + unsigned int flags +) SECP256K1_WARN_UNUSED_RESULT; + +/** Create a secp256k1 context object in caller-provided memory. + * + * The caller must provide a pointer to a rewritable contiguous block of memory + * of size at least secp256k1_context_preallocated_size(flags) bytes, suitably + * aligned to hold an object of any type. + * + * The block of memory is exclusively owned by the created context object during + * the lifetime of this context object, which begins with the call to this + * function and ends when a call to secp256k1_context_preallocated_destroy + * (which destroys the context object again) returns. During the lifetime of the + * context object, the caller is obligated not to access this block of memory, + * i.e., the caller may not read or write the memory, e.g., by copying the memory + * contents to a different location or trying to create a second context object + * in the memory. In simpler words, the prealloc pointer (or any pointer derived + * from it) should not be used during the lifetime of the context object. + * + * Returns: a newly created context object. + * In: prealloc: a pointer to a rewritable contiguous block of memory of + * size at least secp256k1_context_preallocated_size(flags) + * bytes, as detailed above (cannot be NULL) + * flags: which parts of the context to initialize. + * + * See also secp256k1_context_randomize (in secp256k1.h) + * and secp256k1_context_preallocated_destroy. + */ +SECP256K1_API secp256k1_context* secp256k1_context_preallocated_create( + void* prealloc, + unsigned int flags +) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; + +/** Determine the memory size of a secp256k1 context object to be copied into + * caller-provided memory. + * + * Returns: the required size of the caller-provided memory block. + * In: ctx: an existing context to copy (cannot be NULL) + */ +SECP256K1_API size_t secp256k1_context_preallocated_clone_size( + const secp256k1_context* ctx +) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; + +/** Copy a secp256k1 context object into caller-provided memory. + * + * The caller must provide a pointer to a rewritable contiguous block of memory + * of size at least secp256k1_context_preallocated_size(flags) bytes, suitably + * aligned to hold an object of any type. + * + * The block of memory is exclusively owned by the created context object during + * the lifetime of this context object, see the description of + * secp256k1_context_preallocated_create for details. + * + * Returns: a newly created context object. + * Args: ctx: an existing context to copy (cannot be NULL) + * In: prealloc: a pointer to a rewritable contiguous block of memory of + * size at least secp256k1_context_preallocated_size(flags) + * bytes, as detailed above (cannot be NULL) + */ +SECP256K1_API secp256k1_context* secp256k1_context_preallocated_clone( + const secp256k1_context* ctx, + void* prealloc +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_WARN_UNUSED_RESULT; + +/** Destroy a secp256k1 context object that has been created in + * caller-provided memory. + * + * The context pointer may not be used afterwards. + * + * The context to destroy must have been created using + * secp256k1_context_preallocated_create or secp256k1_context_preallocated_clone. + * If the context has instead been created using secp256k1_context_create or + * secp256k1_context_clone, the behaviour is undefined. In that case, + * secp256k1_context_destroy must be used instead. + * + * If required, it is the responsibility of the caller to deallocate the block + * of memory properly after this function returns, e.g., by calling free on the + * preallocated pointer given to secp256k1_context_preallocated_create or + * secp256k1_context_preallocated_clone. + * + * Args: ctx: an existing context to destroy, constructed using + * secp256k1_context_preallocated_create or + * secp256k1_context_preallocated_clone (cannot be NULL) + */ +SECP256K1_API void secp256k1_context_preallocated_destroy( + secp256k1_context* ctx +); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_PREALLOCATED_H */ diff --git a/src/secp256k1/include/secp256k1_schnorrsig.h b/src/secp256k1/include/secp256k1_schnorrsig.h new file mode 100644 index 000000000000..77a9f0bc95d6 --- /dev/null +++ b/src/secp256k1/include/secp256k1_schnorrsig.h @@ -0,0 +1,126 @@ +#ifndef SECP256K1_SCHNORRSIG_H +#define SECP256K1_SCHNORRSIG_H + +#include "secp256k1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** This module implements a variant of Schnorr signatures compliant with + * BIP-schnorr + * (https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki). + */ + +/** Opaque data structure that holds a parsed Schnorr signature. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 64 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage, transmission, or + * comparison, use the `secp256k1_schnorrsig_serialize` and + * `secp256k1_schnorrsig_parse` functions. + */ +typedef struct { + unsigned char data[64]; +} secp256k1_schnorrsig; + +/** Serialize a Schnorr signature. + * + * Returns: 1 + * Args: ctx: a secp256k1 context object + * Out: out64: pointer to a 64-byte array to store the serialized signature + * In: sig: pointer to the signature + * + * See secp256k1_schnorrsig_parse for details about the encoding. + */ +SECP256K1_API int secp256k1_schnorrsig_serialize( + const secp256k1_context* ctx, + unsigned char *out64, + const secp256k1_schnorrsig* sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Parse a Schnorr signature. + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: sig: pointer to a signature object + * In: in64: pointer to the 64-byte signature to be parsed + * + * The signature is serialized in the form R||s, where R is a 32-byte public + * key (x-coordinate only; the y-coordinate is considered to be the unique + * y-coordinate satisfying the curve equation that is a quadratic residue) + * and s is a 32-byte big-endian scalar. + * + * After the call, sig will always be initialized. If parsing failed or the + * encoded numbers are out of range, signature validation with it is + * guaranteed to fail for every message and public key. + */ +SECP256K1_API int secp256k1_schnorrsig_parse( + const secp256k1_context* ctx, + secp256k1_schnorrsig* sig, + const unsigned char *in64 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Create a Schnorr signature. + * + * Returns 1 on success, 0 on failure. + * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * Out: sig: pointer to the returned signature (cannot be NULL) + * In: msg32: the 32-byte message being signed (cannot be NULL) + * seckey: pointer to a 32-byte secret key (cannot be NULL) + * noncefp: pointer to a nonce generation function. If NULL, secp256k1_nonce_function_bipschnorr is used + * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) + */ +SECP256K1_API int secp256k1_schnorrsig_sign( + const secp256k1_context* ctx, + secp256k1_schnorrsig *sig, + const unsigned char *msg32, + const unsigned char *seckey, + secp256k1_nonce_function noncefp, + void *ndata +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Verify a Schnorr signature. + * + * Returns: 1: correct signature + * 0: incorrect or unparseable signature + * Args: ctx: a secp256k1 context object, initialized for verification. + * In: sig: the signature being verified (cannot be NULL) + * msg32: the 32-byte message being verified (cannot be NULL) + * pubkey: pointer to a public key to verify with (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify( + const secp256k1_context* ctx, + const secp256k1_schnorrsig *sig, + const unsigned char *msg32, + const secp256k1_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Verifies a set of Schnorr signatures. + * + * Returns 1 if all succeeded, 0 otherwise. In particular, returns 1 if n_sigs is 0. + * + * Args: ctx: a secp256k1 context object, initialized for verification. + * scratch: scratch space used for the multiexponentiation + * In: sig: array of signatures, or NULL if there are no signatures + * msg32: array of messages, or NULL if there are no signatures + * pk: array of public keys, or NULL if there are no signatures + * n_sigs: number of signatures in above arrays. Must be smaller than + * 2^31 and smaller than half the maximum size_t value. Must be 0 + * if above arrays are NULL. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify_batch( + const secp256k1_context* ctx, + secp256k1_scratch_space *scratch, + const secp256k1_schnorrsig *const *sig, + const unsigned char *const *msg32, + const secp256k1_pubkey *const *pk, + size_t n_sigs +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_SCHNORRSIG_H */ diff --git a/src/secp256k1/src/asm/field_10x26_arm.s b/src/secp256k1/src/asm/field_10x26_arm.s index 5a9cc3ffcfda..9a5bd0672177 100644 --- a/src/secp256k1/src/asm/field_10x26_arm.s +++ b/src/secp256k1/src/asm/field_10x26_arm.s @@ -16,15 +16,9 @@ Note: */ .syntax unified - .arch armv7-a @ eabi attributes - see readelf -A - .eabi_attribute 8, 1 @ Tag_ARM_ISA_use = yes - .eabi_attribute 9, 0 @ Tag_Thumb_ISA_use = no - .eabi_attribute 10, 0 @ Tag_FP_arch = none .eabi_attribute 24, 1 @ Tag_ABI_align_needed = 8-byte .eabi_attribute 25, 1 @ Tag_ABI_align_preserved = 8-byte, except leaf SP - .eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Aggressive Speed - .eabi_attribute 34, 1 @ Tag_CPU_unaligned_access = v6 .text @ Field constants diff --git a/src/secp256k1/src/basic-config.h b/src/secp256k1/src/basic-config.h index fc588061ca40..3a3969d3001d 100644 --- a/src/secp256k1/src/basic-config.h +++ b/src/secp256k1/src/basic-config.h @@ -10,7 +10,10 @@ #ifdef USE_BASIC_CONFIG #undef USE_ASM_X86_64 +#undef USE_ECMULT_STATIC_PRECOMPUTATION #undef USE_ENDOMORPHISM +#undef USE_EXTERNAL_ASM +#undef USE_EXTERNAL_DEFAULT_CALLBACKS #undef USE_FIELD_10X26 #undef USE_FIELD_5X52 #undef USE_FIELD_INV_BUILTIN @@ -27,6 +30,7 @@ #define USE_SCALAR_INV_BUILTIN 1 #define USE_FIELD_10X26 1 #define USE_SCALAR_8X32 1 +#define ECMULT_WINDOW_SIZE 15 #endif /* USE_BASIC_CONFIG */ diff --git a/src/secp256k1/src/bench_ecmult.c b/src/secp256k1/src/bench_ecmult.c index 6d0ed1f4364e..7b5d185dce60 100644 --- a/src/secp256k1/src/bench_ecmult.c +++ b/src/secp256k1/src/bench_ecmult.c @@ -64,7 +64,7 @@ static void bench_ecmult(void* arg) { size_t iter; for (iter = 0; iter < iters; ++iter) { - data->ecmult_multi(&data->ctx->ecmult_ctx, data->scratch, &data->output[iter], data->includes_g ? &data->scalars[data->offset1] : NULL, bench_callback, arg, count - includes_g); + data->ecmult_multi(&data->ctx->error_callback, &data->ctx->ecmult_ctx, data->scratch, &data->output[iter], data->includes_g ? &data->scalars[data->offset1] : NULL, bench_callback, arg, count - includes_g); data->offset1 = (data->offset1 + count) % POINTS; data->offset2 = (data->offset2 + count - 1) % POINTS; } @@ -154,7 +154,7 @@ int main(int argc, char **argv) { } else if(have_flag(argc, argv, "simple")) { printf("Using simple algorithm:\n"); data.ecmult_multi = secp256k1_ecmult_multi_var; - secp256k1_scratch_space_destroy(data.scratch); + secp256k1_scratch_space_destroy(data.ctx, data.scratch); data.scratch = NULL; } else { fprintf(stderr, "%s: unrecognized argument '%s'.\n", argv[0], argv[1]); @@ -193,10 +193,10 @@ int main(int argc, char **argv) { run_test(&data, i << p, 1); } } - secp256k1_context_destroy(data.ctx); if (data.scratch != NULL) { - secp256k1_scratch_space_destroy(data.scratch); + secp256k1_scratch_space_destroy(data.ctx, data.scratch); } + secp256k1_context_destroy(data.ctx); free(data.scalars); free(data.pubkeys); free(data.seckeys); diff --git a/src/secp256k1/src/bench_internal.c b/src/secp256k1/src/bench_internal.c index 9071724331e1..a8f4e9e12f6d 100644 --- a/src/secp256k1/src/bench_internal.c +++ b/src/secp256k1/src/bench_internal.c @@ -253,7 +253,7 @@ void bench_wnaf_const(void* arg) { bench_inv *data = (bench_inv*)arg; for (i = 0; i < 20000; i++) { - secp256k1_wnaf_const(data->wnaf, data->scalar_x, WINDOW_A, 256); + secp256k1_wnaf_const(data->wnaf, &data->scalar_x, WINDOW_A, 256); secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); } } diff --git a/src/secp256k1/src/bench_schnorrsig.c b/src/secp256k1/src/bench_schnorrsig.c new file mode 100644 index 000000000000..b68adf53123a --- /dev/null +++ b/src/secp256k1/src/bench_schnorrsig.c @@ -0,0 +1,128 @@ +/********************************************************************** + * Copyright (c) 2018 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include + +#include "include/secp256k1.h" +#include "include/secp256k1_schnorrsig.h" +#include "util.h" +#include "bench.h" + +#define MAX_SIGS (32768) + +typedef struct { + secp256k1_context *ctx; + secp256k1_scratch_space *scratch; + size_t n; + const unsigned char **pk; + const secp256k1_schnorrsig **sigs; + const unsigned char **msgs; +} bench_schnorrsig_data; + +void bench_schnorrsig_sign(void* arg) { + bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg; + size_t i; + unsigned char sk[32] = "benchmarkexample secrettemplate"; + unsigned char msg[32] = "benchmarkexamplemessagetemplate"; + secp256k1_schnorrsig sig; + + for (i = 0; i < 1000; i++) { + msg[0] = i; + msg[1] = i >> 8; + sk[0] = i; + sk[1] = i >> 8; + CHECK(secp256k1_schnorrsig_sign(data->ctx, &sig, msg, sk, NULL, NULL)); + } +} + +void bench_schnorrsig_verify(void* arg) { + bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg; + size_t i; + + for (i = 0; i < 1000; i++) { + secp256k1_pubkey pk; + CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pk, data->pk[i], 33) == 1); + CHECK(secp256k1_schnorrsig_verify(data->ctx, data->sigs[i], data->msgs[i], &pk)); + } +} + +void bench_schnorrsig_verify_n(void* arg) { + bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg; + size_t i, j; + const secp256k1_pubkey **pk = (const secp256k1_pubkey **)malloc(data->n * sizeof(*pk)); + + CHECK(pk != NULL); + for (j = 0; j < MAX_SIGS/data->n; j++) { + for (i = 0; i < data->n; i++) { + secp256k1_pubkey *pk_nonconst = (secp256k1_pubkey *)malloc(sizeof(*pk_nonconst)); + CHECK(secp256k1_ec_pubkey_parse(data->ctx, pk_nonconst, data->pk[i], 33) == 1); + pk[i] = pk_nonconst; + } + CHECK(secp256k1_schnorrsig_verify_batch(data->ctx, data->scratch, data->sigs, data->msgs, pk, data->n)); + for (i = 0; i < data->n; i++) { + free((void *)pk[i]); + } + } + free(pk); +} + +int main(void) { + size_t i; + bench_schnorrsig_data data; + + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); + data.scratch = secp256k1_scratch_space_create(data.ctx, 1024 * 1024 * 1024); + data.pk = (const unsigned char **)malloc(MAX_SIGS * sizeof(unsigned char *)); + data.msgs = (const unsigned char **)malloc(MAX_SIGS * sizeof(unsigned char *)); + data.sigs = (const secp256k1_schnorrsig **)malloc(MAX_SIGS * sizeof(secp256k1_schnorrsig *)); + + for (i = 0; i < MAX_SIGS; i++) { + unsigned char sk[32]; + unsigned char *msg = (unsigned char *)malloc(32); + secp256k1_schnorrsig *sig = (secp256k1_schnorrsig *)malloc(sizeof(*sig)); + unsigned char *pk_char = (unsigned char *)malloc(33); + secp256k1_pubkey pk; + size_t pk_len = 33; + msg[0] = sk[0] = i; + msg[1] = sk[1] = i >> 8; + msg[2] = sk[2] = i >> 16; + msg[3] = sk[3] = i >> 24; + memset(&msg[4], 'm', 28); + memset(&sk[4], 's', 28); + + data.pk[i] = pk_char; + data.msgs[i] = msg; + data.sigs[i] = sig; + + CHECK(secp256k1_ec_pubkey_create(data.ctx, &pk, sk)); + CHECK(secp256k1_ec_pubkey_serialize(data.ctx, pk_char, &pk_len, &pk, SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_schnorrsig_sign(data.ctx, sig, msg, sk, NULL, NULL)); + } + + run_benchmark("schnorrsig_sign", bench_schnorrsig_sign, NULL, NULL, (void *) &data, 10, 1000); + run_benchmark("schnorrsig_verify", bench_schnorrsig_verify, NULL, NULL, (void *) &data, 10, 1000); + for (i = 1; i <= MAX_SIGS; i *= 2) { + char name[64]; + sprintf(name, "schnorrsig_batch_verify_%d", (int) i); + + data.n = i; + run_benchmark(name, bench_schnorrsig_verify_n, NULL, NULL, (void *) &data, 3, MAX_SIGS); + } + + for (i = 0; i < MAX_SIGS; i++) { + free((void *)data.pk[i]); + free((void *)data.msgs[i]); + free((void *)data.sigs[i]); + } + free(data.pk); + free(data.msgs); + free(data.sigs); + + secp256k1_scratch_space_destroy(data.ctx, data.scratch); + secp256k1_context_destroy(data.ctx); + return 0; +} diff --git a/src/secp256k1/src/ecdsa_impl.h b/src/secp256k1/src/ecdsa_impl.h index c3400042d839..eb099c87dc83 100644 --- a/src/secp256k1/src/ecdsa_impl.h +++ b/src/secp256k1/src/ecdsa_impl.h @@ -46,68 +46,73 @@ static const secp256k1_fe secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CON 0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL ); -static int secp256k1_der_read_len(const unsigned char **sigp, const unsigned char *sigend) { - int lenleft, b1; - size_t ret = 0; +static int secp256k1_der_read_len(size_t *len, const unsigned char **sigp, const unsigned char *sigend) { + size_t lenleft; + unsigned char b1; + VERIFY_CHECK(len != NULL); + *len = 0; if (*sigp >= sigend) { - return -1; + return 0; } b1 = *((*sigp)++); if (b1 == 0xFF) { /* X.690-0207 8.1.3.5.c the value 0xFF shall not be used. */ - return -1; + return 0; } if ((b1 & 0x80) == 0) { /* X.690-0207 8.1.3.4 short form length octets */ - return b1; + *len = b1; + return 1; } if (b1 == 0x80) { /* Indefinite length is not allowed in DER. */ - return -1; + return 0; } /* X.690-207 8.1.3.5 long form length octets */ - lenleft = b1 & 0x7F; - if (lenleft > sigend - *sigp) { - return -1; + lenleft = b1 & 0x7F; /* lenleft is at least 1 */ + if (lenleft > (size_t)(sigend - *sigp)) { + return 0; } if (**sigp == 0) { /* Not the shortest possible length encoding. */ - return -1; + return 0; } - if ((size_t)lenleft > sizeof(size_t)) { + if (lenleft > sizeof(size_t)) { /* The resulting length would exceed the range of a size_t, so * certainly longer than the passed array size. */ - return -1; + return 0; } while (lenleft > 0) { - ret = (ret << 8) | **sigp; - if (ret + lenleft > (size_t)(sigend - *sigp)) { - /* Result exceeds the length of the passed array. */ - return -1; - } + *len = (*len << 8) | **sigp; (*sigp)++; lenleft--; } - if (ret < 128) { + if (*len > (size_t)(sigend - *sigp)) { + /* Result exceeds the length of the passed array. */ + return 0; + } + if (*len < 128) { /* Not the shortest possible length encoding. */ - return -1; + return 0; } - return ret; + return 1; } static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char **sig, const unsigned char *sigend) { int overflow = 0; unsigned char ra[32] = {0}; - int rlen; + size_t rlen; if (*sig == sigend || **sig != 0x02) { /* Not a primitive integer (X.690-0207 8.3.1). */ return 0; } (*sig)++; - rlen = secp256k1_der_read_len(sig, sigend); - if (rlen <= 0 || (*sig) + rlen > sigend) { + if (secp256k1_der_read_len(&rlen, sig, sigend) == 0) { + return 0; + } + if (rlen == 0 || *sig + rlen > sigend) { /* Exceeds bounds or not at least length 1 (X.690-0207 8.3.1). */ return 0; } @@ -123,8 +128,11 @@ static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char /* Negative. */ overflow = 1; } - while (rlen > 0 && **sig == 0) { - /* Skip leading zero bytes */ + /* There is at most one leading zero byte: + * if there were two leading zero bytes, we would have failed and returned 0 + * because of excessive 0x00 padding already. */ + if (rlen > 0 && **sig == 0) { + /* Skip leading zero byte */ rlen--; (*sig)++; } @@ -144,18 +152,16 @@ static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *rr, secp256k1_scalar *rs, const unsigned char *sig, size_t size) { const unsigned char *sigend = sig + size; - int rlen; + size_t rlen; if (sig == sigend || *(sig++) != 0x30) { /* The encoding doesn't start with a constructed sequence (X.690-0207 8.9.1). */ return 0; } - rlen = secp256k1_der_read_len(&sig, sigend); - if (rlen < 0 || sig + rlen > sigend) { - /* Tuple exceeds bounds */ + if (secp256k1_der_read_len(&rlen, &sig, sigend) == 0) { return 0; } - if (sig + rlen != sigend) { - /* Garbage after tuple. */ + if (rlen != (size_t)(sigend - sig)) { + /* Tuple exceeds bounds or garage after tuple. */ return 0; } diff --git a/src/secp256k1/src/ecmult.h b/src/secp256k1/src/ecmult.h index 3d75a960f424..c9b198239d88 100644 --- a/src/secp256k1/src/ecmult.h +++ b/src/secp256k1/src/ecmult.h @@ -20,10 +20,10 @@ typedef struct { #endif } secp256k1_ecmult_context; +static const size_t SECP256K1_ECMULT_CONTEXT_PREALLOCATED_SIZE; static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx); -static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb); -static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst, - const secp256k1_ecmult_context *src, const secp256k1_callback *cb); +static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, void **prealloc); +static void secp256k1_ecmult_context_finalize_memcpy(secp256k1_ecmult_context *dst, const secp256k1_ecmult_context *src); static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx); static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx); @@ -43,6 +43,6 @@ typedef int (secp256k1_ecmult_multi_callback)(secp256k1_scalar *sc, secp256k1_ge * 0 if there is not enough scratch space for a single point or * callback returns 0 */ -static int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n); +static int secp256k1_ecmult_multi_var(const secp256k1_callback* error_callback, const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n); #endif /* SECP256K1_ECMULT_H */ diff --git a/src/secp256k1/src/ecmult_const_impl.h b/src/secp256k1/src/ecmult_const_impl.h index 8411752eb069..aaa576ada4cc 100644 --- a/src/secp256k1/src/ecmult_const_impl.h +++ b/src/secp256k1/src/ecmult_const_impl.h @@ -48,7 +48,7 @@ * * Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335 */ -static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w, int size) { +static int secp256k1_wnaf_const(int *wnaf, const secp256k1_scalar *scalar, int w, int size) { int global_sign; int skew = 0; int word = 0; @@ -59,8 +59,12 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w, int size) int flip; int bit; - secp256k1_scalar neg_s; + secp256k1_scalar s; int not_neg_one; + + VERIFY_CHECK(w > 0); + VERIFY_CHECK(size > 0); + /* Note that we cannot handle even numbers by negating them to be odd, as is * done in other implementations, since if our scalars were specified to have * width < 256 for performance reasons, their negations would have width 256 @@ -75,12 +79,13 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w, int size) * {1, 2} we want to add to the scalar when ensuring that it's odd. Further * complicating things, -1 interacts badly with `secp256k1_scalar_cadd_bit` and * we need to special-case it in this logic. */ - flip = secp256k1_scalar_is_high(&s); + flip = secp256k1_scalar_is_high(scalar); /* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */ - bit = flip ^ !secp256k1_scalar_is_even(&s); + bit = flip ^ !secp256k1_scalar_is_even(scalar); /* We check for negative one, since adding 2 to it will cause an overflow */ - secp256k1_scalar_negate(&neg_s, &s); - not_neg_one = !secp256k1_scalar_is_one(&neg_s); + secp256k1_scalar_negate(&s, scalar); + not_neg_one = !secp256k1_scalar_is_one(&s); + s = *scalar; secp256k1_scalar_cadd_bit(&s, bit, not_neg_one); /* If we had negative one, flip == 1, s.d[0] == 0, bit == 1, so caller expects * that we added two to it and flipped it. In fact for -1 these operations are @@ -93,7 +98,7 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w, int size) /* 4 */ u_last = secp256k1_scalar_shr_int(&s, w); - while (word * w < size) { + do { int sign; int even; @@ -109,7 +114,7 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w, int size) wnaf[word++] = u_last * global_sign; u_last = u; - } + } while (word * w < size); wnaf[word] = u * global_sign; VERIFY_CHECK(secp256k1_scalar_is_zero(&s)); @@ -132,7 +137,6 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)]; int i; - secp256k1_scalar sc = *scalar; /* build wnaf representation for q. */ int rsize = size; @@ -140,13 +144,13 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons if (size > 128) { rsize = 128; /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */ - secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc); - skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1, 128); - skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1, 128); + secp256k1_scalar_split_lambda(&q_1, &q_lam, scalar); + skew_1 = secp256k1_wnaf_const(wnaf_1, &q_1, WINDOW_A - 1, 128); + skew_lam = secp256k1_wnaf_const(wnaf_lam, &q_lam, WINDOW_A - 1, 128); } else #endif { - skew_1 = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1, size); + skew_1 = secp256k1_wnaf_const(wnaf_1, scalar, WINDOW_A - 1, size); #ifdef USE_ENDOMORPHISM skew_lam = 0; #endif diff --git a/src/secp256k1/src/ecmult_gen.h b/src/secp256k1/src/ecmult_gen.h index 7564b7015f0b..b136e94632dd 100644 --- a/src/secp256k1/src/ecmult_gen.h +++ b/src/secp256k1/src/ecmult_gen.h @@ -28,10 +28,10 @@ typedef struct { secp256k1_gej initial; } secp256k1_ecmult_gen_context; +static const size_t SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE; static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context* ctx); -static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, const secp256k1_callback* cb); -static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst, - const secp256k1_ecmult_gen_context* src, const secp256k1_callback* cb); +static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, void **prealloc); +static void secp256k1_ecmult_gen_context_finalize_memcpy(secp256k1_ecmult_gen_context *dst, const secp256k1_ecmult_gen_context* src); static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context* ctx); static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx); diff --git a/src/secp256k1/src/ecmult_gen_impl.h b/src/secp256k1/src/ecmult_gen_impl.h index d64505dc0010..0e2eafa71de3 100644 --- a/src/secp256k1/src/ecmult_gen_impl.h +++ b/src/secp256k1/src/ecmult_gen_impl.h @@ -7,6 +7,7 @@ #ifndef SECP256K1_ECMULT_GEN_IMPL_H #define SECP256K1_ECMULT_GEN_IMPL_H +#include "util.h" #include "scalar.h" #include "group.h" #include "ecmult_gen.h" @@ -14,23 +15,32 @@ #ifdef USE_ECMULT_STATIC_PRECOMPUTATION #include "ecmult_static_context.h" #endif + +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION + static const size_t SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE = ROUND_TO_ALIGN(sizeof(*((secp256k1_ecmult_gen_context*) NULL)->prec)); +#else + static const size_t SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE = 0; +#endif + static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context *ctx) { ctx->prec = NULL; } -static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, const secp256k1_callback* cb) { +static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, void **prealloc) { #ifndef USE_ECMULT_STATIC_PRECOMPUTATION secp256k1_ge prec[1024]; secp256k1_gej gj; secp256k1_gej nums_gej; int i, j; + size_t const prealloc_size = SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE; + void* const base = *prealloc; #endif if (ctx->prec != NULL) { return; } #ifndef USE_ECMULT_STATIC_PRECOMPUTATION - ctx->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*ctx->prec)); + ctx->prec = (secp256k1_ge_storage (*)[64][16])manual_alloc(prealloc, prealloc_size, base, prealloc_size); /* get the generator */ secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); @@ -85,7 +95,7 @@ static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx } } #else - (void)cb; + (void)prealloc; ctx->prec = (secp256k1_ge_storage (*)[64][16])secp256k1_ecmult_static_context; #endif secp256k1_ecmult_gen_blind(ctx, NULL); @@ -95,27 +105,18 @@ static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_cont return ctx->prec != NULL; } -static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst, - const secp256k1_ecmult_gen_context *src, const secp256k1_callback* cb) { - if (src->prec == NULL) { - dst->prec = NULL; - } else { +static void secp256k1_ecmult_gen_context_finalize_memcpy(secp256k1_ecmult_gen_context *dst, const secp256k1_ecmult_gen_context *src) { #ifndef USE_ECMULT_STATIC_PRECOMPUTATION - dst->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*dst->prec)); - memcpy(dst->prec, src->prec, sizeof(*dst->prec)); + if (src->prec != NULL) { + /* We cast to void* first to suppress a -Wcast-align warning. */ + dst->prec = (secp256k1_ge_storage (*)[64][16])(void*)((unsigned char*)dst + ((unsigned char*)src->prec - (unsigned char*)src)); + } #else - (void)cb; - dst->prec = src->prec; + (void)dst, (void)src; #endif - dst->initial = src->initial; - dst->blind = src->blind; - } } static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) { -#ifndef USE_ECMULT_STATIC_PRECOMPUTATION - free(ctx->prec); -#endif secp256k1_scalar_clear(&ctx->blind); secp256k1_gej_clear(&ctx->initial); ctx->prec = NULL; @@ -186,7 +187,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const do { secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); retry = !secp256k1_fe_set_b32(&s, nonce32); - retry |= secp256k1_fe_is_zero(&s); + retry = retry || secp256k1_fe_is_zero(&s); } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > Fp. */ /* Randomize the projection to defend against multiplier sidechannels. */ secp256k1_gej_rescale(&ctx->initial, &s); @@ -195,7 +196,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); secp256k1_scalar_set_b32(&b, nonce32, &retry); /* A blinding value of 0 works, but would undermine the projection hardening. */ - retry |= secp256k1_scalar_is_zero(&b); + retry = retry || secp256k1_scalar_is_zero(&b); } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > order. */ secp256k1_rfc6979_hmac_sha256_finalize(&rng); memset(nonce32, 0, 32); diff --git a/src/secp256k1/src/ecmult_impl.h b/src/secp256k1/src/ecmult_impl.h index 1986914a4fd5..bb7adedfb1f0 100644 --- a/src/secp256k1/src/ecmult_impl.h +++ b/src/secp256k1/src/ecmult_impl.h @@ -10,6 +10,7 @@ #include #include +#include "util.h" #include "group.h" #include "scalar.h" #include "ecmult.h" @@ -30,16 +31,32 @@ # endif #else /* optimal for 128-bit and 256-bit exponents. */ -#define WINDOW_A 5 -/** larger numbers may result in slightly better performance, at the cost of - exponentially larger precomputed tables. */ -#ifdef USE_ENDOMORPHISM -/** Two tables for window size 15: 1.375 MiB. */ -#define WINDOW_G 15 -#else -/** One table for window size 16: 1.375 MiB. */ -#define WINDOW_G 16 +# define WINDOW_A 5 +/** Larger values for ECMULT_WINDOW_SIZE result in possibly better + * performance at the cost of an exponentially larger precomputed + * table. The exact table size is + * (1 << (WINDOW_G - 2)) * sizeof(secp256k1_ge_storage) bytes, + * where sizeof(secp256k1_ge_storage) is typically 64 bytes but can + * be larger due to platform-specific padding and alignment. + * If the endomorphism optimization is enabled (USE_ENDOMORMPHSIM) + * two tables of this size are used instead of only one. + */ +# define WINDOW_G ECMULT_WINDOW_SIZE #endif + +/* Noone will ever need more than a window size of 24. The code might + * be correct for larger values of ECMULT_WINDOW_SIZE but this is not + * not tested. + * + * The following limitations are known, and there are probably more: + * If WINDOW_G > 27 and size_t has 32 bits, then the code is incorrect + * because the size of the memory object that we allocate (in bytes) + * will not fit in a size_t. + * If WINDOW_G > 31 and int has 32 bits, then the code is incorrect + * because certain expressions will overflow. + */ +#if ECMULT_WINDOW_SIZE < 2 || ECMULT_WINDOW_SIZE > 24 +# error Set ECMULT_WINDOW_SIZE to an integer in range [2..24]. #endif #ifdef USE_ENDOMORPHISM @@ -294,6 +311,13 @@ static void secp256k1_ecmult_odd_multiples_table_storage_var(const int n, secp25 } \ } while(0) +static const size_t SECP256K1_ECMULT_CONTEXT_PREALLOCATED_SIZE = + ROUND_TO_ALIGN(sizeof((*((secp256k1_ecmult_context*) NULL)->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)) +#ifdef USE_ENDOMORPHISM + + ROUND_TO_ALIGN(sizeof((*((secp256k1_ecmult_context*) NULL)->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)) +#endif + ; + static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx) { ctx->pre_g = NULL; #ifdef USE_ENDOMORPHISM @@ -301,8 +325,10 @@ static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx) { #endif } -static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb) { +static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, void **prealloc) { secp256k1_gej gj; + void* const base = *prealloc; + size_t const prealloc_size = SECP256K1_ECMULT_CONTEXT_PREALLOCATED_SIZE; if (ctx->pre_g != NULL) { return; @@ -311,7 +337,12 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const /* get the generator */ secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); - ctx->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); + { + size_t size = sizeof((*ctx->pre_g)[0]) * ((size_t)ECMULT_TABLE_SIZE(WINDOW_G)); + /* check for overflow */ + VERIFY_CHECK(size / sizeof((*ctx->pre_g)[0]) == ((size_t)ECMULT_TABLE_SIZE(WINDOW_G))); + ctx->pre_g = (secp256k1_ge_storage (*)[])manual_alloc(prealloc, sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G), base, prealloc_size); + } /* precompute the tables with odd multiples */ secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g, &gj); @@ -321,7 +352,10 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_gej g_128j; int i; - ctx->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, sizeof((*ctx->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); + size_t size = sizeof((*ctx->pre_g_128)[0]) * ((size_t) ECMULT_TABLE_SIZE(WINDOW_G)); + /* check for overflow */ + VERIFY_CHECK(size / sizeof((*ctx->pre_g_128)[0]) == ((size_t)ECMULT_TABLE_SIZE(WINDOW_G))); + ctx->pre_g_128 = (secp256k1_ge_storage (*)[])manual_alloc(prealloc, sizeof((*ctx->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G), base, prealloc_size); /* calculate 2^128*generator */ g_128j = gj; @@ -333,22 +367,14 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const #endif } -static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst, - const secp256k1_ecmult_context *src, const secp256k1_callback *cb) { - if (src->pre_g == NULL) { - dst->pre_g = NULL; - } else { - size_t size = sizeof((*dst->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G); - dst->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, size); - memcpy(dst->pre_g, src->pre_g, size); +static void secp256k1_ecmult_context_finalize_memcpy(secp256k1_ecmult_context *dst, const secp256k1_ecmult_context *src) { + if (src->pre_g != NULL) { + /* We cast to void* first to suppress a -Wcast-align warning. */ + dst->pre_g = (secp256k1_ge_storage (*)[])(void*)((unsigned char*)dst + ((unsigned char*)(src->pre_g) - (unsigned char*)src)); } #ifdef USE_ENDOMORPHISM - if (src->pre_g_128 == NULL) { - dst->pre_g_128 = NULL; - } else { - size_t size = sizeof((*dst->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G); - dst->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, size); - memcpy(dst->pre_g_128, src->pre_g_128, size); + if (src->pre_g_128 != NULL) { + dst->pre_g_128 = (secp256k1_ge_storage (*)[])(void*)((unsigned char*)dst + ((unsigned char*)(src->pre_g_128) - (unsigned char*)src)); } #endif } @@ -358,10 +384,6 @@ static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx } static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx) { - free(ctx->pre_g); -#ifdef USE_ENDOMORPHISM - free(ctx->pre_g_128); -#endif secp256k1_ecmult_context_init(ctx); } @@ -418,7 +440,7 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a, CHECK(carry == 0); while (bit < 256) { CHECK(secp256k1_scalar_get_bits(&s, bit++, 1) == 0); - } + } #endif return last_set_bit + 1; } @@ -626,52 +648,55 @@ static size_t secp256k1_strauss_scratch_size(size_t n_points) { return n_points*point_size; } -static int secp256k1_ecmult_strauss_batch(const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) { +static int secp256k1_ecmult_strauss_batch(const secp256k1_callback* error_callback, const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) { secp256k1_gej* points; secp256k1_scalar* scalars; struct secp256k1_strauss_state state; size_t i; + const size_t scratch_checkpoint = secp256k1_scratch_checkpoint(error_callback, scratch); secp256k1_gej_set_infinity(r); if (inp_g_sc == NULL && n_points == 0) { return 1; } - if (!secp256k1_scratch_allocate_frame(scratch, secp256k1_strauss_scratch_size(n_points), STRAUSS_SCRATCH_OBJECTS)) { - return 0; - } - points = (secp256k1_gej*)secp256k1_scratch_alloc(scratch, n_points * sizeof(secp256k1_gej)); - scalars = (secp256k1_scalar*)secp256k1_scratch_alloc(scratch, n_points * sizeof(secp256k1_scalar)); - state.prej = (secp256k1_gej*)secp256k1_scratch_alloc(scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_gej)); - state.zr = (secp256k1_fe*)secp256k1_scratch_alloc(scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_fe)); + points = (secp256k1_gej*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_gej)); + scalars = (secp256k1_scalar*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_scalar)); + state.prej = (secp256k1_gej*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_gej)); + state.zr = (secp256k1_fe*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_fe)); #ifdef USE_ENDOMORPHISM - state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(scratch, n_points * 2 * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge)); + state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(error_callback, scratch, n_points * 2 * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge)); state.pre_a_lam = state.pre_a + n_points * ECMULT_TABLE_SIZE(WINDOW_A); #else - state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge)); + state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge)); #endif - state.ps = (struct secp256k1_strauss_point_state*)secp256k1_scratch_alloc(scratch, n_points * sizeof(struct secp256k1_strauss_point_state)); + state.ps = (struct secp256k1_strauss_point_state*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(struct secp256k1_strauss_point_state)); + + if (points == NULL || scalars == NULL || state.prej == NULL || state.zr == NULL || state.pre_a == NULL) { + secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); + return 0; + } for (i = 0; i < n_points; i++) { secp256k1_ge point; if (!cb(&scalars[i], &point, i+cb_offset, cbdata)) { - secp256k1_scratch_deallocate_frame(scratch); + secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); return 0; } secp256k1_gej_set_ge(&points[i], &point); } secp256k1_ecmult_strauss_wnaf(ctx, &state, r, n_points, points, scalars, inp_g_sc); - secp256k1_scratch_deallocate_frame(scratch); + secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); return 1; } /* Wrapper for secp256k1_ecmult_multi_func interface */ -static int secp256k1_ecmult_strauss_batch_single(const secp256k1_ecmult_context *actx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) { - return secp256k1_ecmult_strauss_batch(actx, scratch, r, inp_g_sc, cb, cbdata, n, 0); +static int secp256k1_ecmult_strauss_batch_single(const secp256k1_callback* error_callback, const secp256k1_ecmult_context *actx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) { + return secp256k1_ecmult_strauss_batch(error_callback, actx, scratch, r, inp_g_sc, cb, cbdata, n, 0); } -static size_t secp256k1_strauss_max_points(secp256k1_scratch *scratch) { - return secp256k1_scratch_max_allocation(scratch, STRAUSS_SCRATCH_OBJECTS) / secp256k1_strauss_scratch_size(1); +static size_t secp256k1_strauss_max_points(const secp256k1_callback* error_callback, secp256k1_scratch *scratch) { + return secp256k1_scratch_max_allocation(error_callback, scratch, STRAUSS_SCRATCH_OBJECTS) / secp256k1_strauss_scratch_size(1); } /** Convert a number to WNAF notation. @@ -963,7 +988,8 @@ static size_t secp256k1_pippenger_scratch_size(size_t n_points, int bucket_windo return (sizeof(secp256k1_gej) << bucket_window) + sizeof(struct secp256k1_pippenger_state) + entries * entry_size; } -static int secp256k1_ecmult_pippenger_batch(const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) { +static int secp256k1_ecmult_pippenger_batch(const secp256k1_callback* error_callback, const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) { + const size_t scratch_checkpoint = secp256k1_scratch_checkpoint(error_callback, scratch); /* Use 2(n+1) with the endomorphism, n+1 without, when calculating batch * sizes. The reason for +1 is that we add the G scalar to the list of * other scalars. */ @@ -988,15 +1014,21 @@ static int secp256k1_ecmult_pippenger_batch(const secp256k1_ecmult_context *ctx, } bucket_window = secp256k1_pippenger_bucket_window(n_points); - if (!secp256k1_scratch_allocate_frame(scratch, secp256k1_pippenger_scratch_size(n_points, bucket_window), PIPPENGER_SCRATCH_OBJECTS)) { + points = (secp256k1_ge *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*points)); + scalars = (secp256k1_scalar *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*scalars)); + state_space = (struct secp256k1_pippenger_state *) secp256k1_scratch_alloc(error_callback, scratch, sizeof(*state_space)); + if (points == NULL || scalars == NULL || state_space == NULL) { + secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); + return 0; + } + + state_space->ps = (struct secp256k1_pippenger_point_state *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*state_space->ps)); + state_space->wnaf_na = (int *) secp256k1_scratch_alloc(error_callback, scratch, entries*(WNAF_SIZE(bucket_window+1)) * sizeof(int)); + buckets = (secp256k1_gej *) secp256k1_scratch_alloc(error_callback, scratch, (1<ps == NULL || state_space->wnaf_na == NULL || buckets == NULL) { + secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); return 0; } - points = (secp256k1_ge *) secp256k1_scratch_alloc(scratch, entries * sizeof(*points)); - scalars = (secp256k1_scalar *) secp256k1_scratch_alloc(scratch, entries * sizeof(*scalars)); - state_space = (struct secp256k1_pippenger_state *) secp256k1_scratch_alloc(scratch, sizeof(*state_space)); - state_space->ps = (struct secp256k1_pippenger_point_state *) secp256k1_scratch_alloc(scratch, entries * sizeof(*state_space->ps)); - state_space->wnaf_na = (int *) secp256k1_scratch_alloc(scratch, entries*(WNAF_SIZE(bucket_window+1)) * sizeof(int)); - buckets = (secp256k1_gej *) secp256k1_scratch_alloc(scratch, sizeof(*buckets) << bucket_window); if (inp_g_sc != NULL) { scalars[0] = *inp_g_sc; @@ -1010,7 +1042,7 @@ static int secp256k1_ecmult_pippenger_batch(const secp256k1_ecmult_context *ctx, while (point_idx < n_points) { if (!cb(&scalars[idx], &points[idx], point_idx + cb_offset, cbdata)) { - secp256k1_scratch_deallocate_frame(scratch); + secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); return 0; } idx++; @@ -1034,13 +1066,13 @@ static int secp256k1_ecmult_pippenger_batch(const secp256k1_ecmult_context *ctx, for(i = 0; i < 1<= ECMULT_PIPPENGER_THRESHOLD) { f = secp256k1_ecmult_pippenger_batch; } else { - if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_strauss_max_points(scratch), n)) { - return 0; + if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_strauss_max_points(error_callback, scratch), n)) { + return secp256k1_ecmult_multi_simple_var(ctx, r, inp_g_sc, cb, cbdata, n); } f = secp256k1_ecmult_strauss_batch; } @@ -1169,7 +1203,7 @@ static int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp2 size_t nbp = n < n_batch_points ? n : n_batch_points; size_t offset = n_batch_points*i; secp256k1_gej tmp; - if (!f(ctx, scratch, &tmp, i == 0 ? inp_g_sc : NULL, cb, cbdata, nbp, offset)) { + if (!f(error_callback, ctx, scratch, &tmp, i == 0 ? inp_g_sc : NULL, cb, cbdata, nbp, offset)) { return 0; } secp256k1_gej_add_var(r, r, &tmp, NULL); diff --git a/src/secp256k1/src/gen_context.c b/src/secp256k1/src/gen_context.c index 87d296ebf0e2..82c605c5d4f7 100644 --- a/src/secp256k1/src/gen_context.c +++ b/src/secp256k1/src/gen_context.c @@ -8,6 +8,7 @@ #include "basic-config.h" #include "include/secp256k1.h" +#include "util.h" #include "field_impl.h" #include "scalar_impl.h" #include "group_impl.h" @@ -26,6 +27,7 @@ static const secp256k1_callback default_error_callback = { int main(int argc, char **argv) { secp256k1_ecmult_gen_context ctx; + void *prealloc, *base; int inner; int outer; FILE* fp; @@ -38,15 +40,17 @@ int main(int argc, char **argv) { fprintf(stderr, "Could not open src/ecmult_static_context.h for writing!\n"); return -1; } - + fprintf(fp, "#ifndef _SECP256K1_ECMULT_STATIC_CONTEXT_\n"); fprintf(fp, "#define _SECP256K1_ECMULT_STATIC_CONTEXT_\n"); fprintf(fp, "#include \"src/group.h\"\n"); fprintf(fp, "#define SC SECP256K1_GE_STORAGE_CONST\n"); fprintf(fp, "static const secp256k1_ge_storage secp256k1_ecmult_static_context[64][16] = {\n"); + base = checked_malloc(&default_error_callback, SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE); + prealloc = base; secp256k1_ecmult_gen_context_init(&ctx); - secp256k1_ecmult_gen_context_build(&ctx, &default_error_callback); + secp256k1_ecmult_gen_context_build(&ctx, &prealloc); for(outer = 0; outer != 64; outer++) { fprintf(fp,"{\n"); for(inner = 0; inner != 16; inner++) { @@ -65,10 +69,11 @@ int main(int argc, char **argv) { } fprintf(fp,"};\n"); secp256k1_ecmult_gen_context_clear(&ctx); - + free(base); + fprintf(fp, "#undef SC\n"); fprintf(fp, "#endif\n"); fclose(fp); - + return 0; } diff --git a/src/secp256k1/src/hash_impl.h b/src/secp256k1/src/hash_impl.h index 009f26beba93..782f97216c28 100644 --- a/src/secp256k1/src/hash_impl.h +++ b/src/secp256k1/src/hash_impl.h @@ -131,7 +131,8 @@ static void secp256k1_sha256_transform(uint32_t* s, const uint32_t* chunk) { static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t len) { size_t bufsize = hash->bytes & 0x3F; hash->bytes += len; - while (bufsize + len >= 64) { + VERIFY_CHECK(hash->bytes >= len); + while (len >= 64 - bufsize) { /* Fill the buffer, and process it. */ size_t chunk_len = 64 - bufsize; memcpy(((unsigned char*)hash->buf) + bufsize, data, chunk_len); diff --git a/src/secp256k1/src/modules/recovery/main_impl.h b/src/secp256k1/src/modules/recovery/main_impl.h index 2f6691c5a130..ed356e53a5c8 100755 --- a/src/secp256k1/src/modules/recovery/main_impl.h +++ b/src/secp256k1/src/modules/recovery/main_impl.h @@ -147,7 +147,7 @@ int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecd break; } secp256k1_scalar_set_b32(&non, nonce32, &overflow); - if (!secp256k1_scalar_is_zero(&non) && !overflow) { + if (!overflow && !secp256k1_scalar_is_zero(&non)) { if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) { break; } diff --git a/src/secp256k1/src/modules/schnorrsig/Makefile.am.include b/src/secp256k1/src/modules/schnorrsig/Makefile.am.include new file mode 100644 index 000000000000..a82bafe43fda --- /dev/null +++ b/src/secp256k1/src/modules/schnorrsig/Makefile.am.include @@ -0,0 +1,8 @@ +include_HEADERS += include/secp256k1_schnorrsig.h +noinst_HEADERS += src/modules/schnorrsig/main_impl.h +noinst_HEADERS += src/modules/schnorrsig/tests_impl.h +if USE_BENCHMARK +noinst_PROGRAMS += bench_schnorrsig +bench_schnorrsig_SOURCES = src/bench_schnorrsig.c +bench_schnorrsig_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) +endif diff --git a/src/secp256k1/src/modules/schnorrsig/main_impl.h b/src/secp256k1/src/modules/schnorrsig/main_impl.h new file mode 100644 index 000000000000..739e98b0c346 --- /dev/null +++ b/src/secp256k1/src/modules/schnorrsig/main_impl.h @@ -0,0 +1,332 @@ +/********************************************************************** + * Copyright (c) 2018 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_MODULE_SCHNORRSIG_MAIN_ +#define _SECP256K1_MODULE_SCHNORRSIG_MAIN_ + +#include "include/secp256k1.h" +#include "include/secp256k1_schnorrsig.h" +#include "hash.h" + +int secp256k1_schnorrsig_serialize(const secp256k1_context* ctx, unsigned char *out64, const secp256k1_schnorrsig* sig) { + (void) ctx; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(out64 != NULL); + ARG_CHECK(sig != NULL); + memcpy(out64, sig->data, 64); + return 1; +} + +int secp256k1_schnorrsig_parse(const secp256k1_context* ctx, secp256k1_schnorrsig* sig, const unsigned char *in64) { + (void) ctx; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(in64 != NULL); + memcpy(sig->data, in64, 64); + return 1; +} + +int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, secp256k1_schnorrsig *sig, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, void *ndata) { + secp256k1_scalar x; + secp256k1_scalar e; + secp256k1_scalar k; + secp256k1_gej pkj; + secp256k1_gej rj; + secp256k1_ge pk; + secp256k1_ge r; + secp256k1_sha256 sha; + int overflow; + unsigned char buf[33]; + size_t buflen = sizeof(buf); + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(sig != NULL); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(seckey != NULL); + + if (noncefp == NULL) { + noncefp = secp256k1_nonce_function_bipschnorr; + } + secp256k1_scalar_set_b32(&x, seckey, &overflow); + /* Fail if the secret key is invalid. */ + if (overflow || secp256k1_scalar_is_zero(&x)) { + memset(sig, 0, sizeof(*sig)); + return 0; + } + + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pkj, &x); + secp256k1_ge_set_gej(&pk, &pkj); + + if (!noncefp(buf, msg32, seckey, NULL, (void*)ndata, 0)) { + return 0; + } + secp256k1_scalar_set_b32(&k, buf, NULL); + if (secp256k1_scalar_is_zero(&k)) { + return 0; + } + + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &k); + secp256k1_ge_set_gej(&r, &rj); + + if (!secp256k1_fe_is_quad_var(&r.y)) { + secp256k1_scalar_negate(&k, &k); + } + secp256k1_fe_normalize(&r.x); + secp256k1_fe_get_b32(&sig->data[0], &r.x); + + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, &sig->data[0], 32); + secp256k1_eckey_pubkey_serialize(&pk, buf, &buflen, 1); + secp256k1_sha256_write(&sha, buf, buflen); + secp256k1_sha256_write(&sha, msg32, 32); + secp256k1_sha256_finalize(&sha, buf); + + secp256k1_scalar_set_b32(&e, buf, NULL); + secp256k1_scalar_mul(&e, &e, &x); + secp256k1_scalar_add(&e, &e, &k); + + secp256k1_scalar_get_b32(&sig->data[32], &e); + secp256k1_scalar_clear(&k); + secp256k1_scalar_clear(&x); + + return 1; +} + +/* Helper function for verification and batch verification. + * Computes R = sG - eP. */ +static int secp256k1_schnorrsig_real_verify(const secp256k1_context* ctx, secp256k1_gej *rj, const secp256k1_scalar *s, const secp256k1_scalar *e, const secp256k1_pubkey *pk) { + secp256k1_scalar nege; + secp256k1_ge pkp; + secp256k1_gej pkj; + + secp256k1_scalar_negate(&nege, e); + + if (!secp256k1_pubkey_load(ctx, &pkp, pk)) { + return 0; + } + secp256k1_gej_set_ge(&pkj, &pkp); + + /* rj = s*G + (-e)*pkj */ + secp256k1_ecmult(&ctx->ecmult_ctx, rj, &pkj, &nege, s); + return 1; +} + +int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const secp256k1_schnorrsig *sig, const unsigned char *msg32, const secp256k1_pubkey *pk) { + secp256k1_scalar s; + secp256k1_scalar e; + secp256k1_gej rj; + secp256k1_fe rx; + secp256k1_sha256 sha; + unsigned char buf[33]; + size_t buflen = sizeof(buf); + int overflow; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(sig != NULL); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(pk != NULL); + + if (!secp256k1_fe_set_b32(&rx, &sig->data[0])) { + return 0; + } + + secp256k1_scalar_set_b32(&s, &sig->data[32], &overflow); + if (overflow) { + return 0; + } + + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, &sig->data[0], 32); + secp256k1_ec_pubkey_serialize(ctx, buf, &buflen, pk, SECP256K1_EC_COMPRESSED); + secp256k1_sha256_write(&sha, buf, buflen); + secp256k1_sha256_write(&sha, msg32, 32); + secp256k1_sha256_finalize(&sha, buf); + secp256k1_scalar_set_b32(&e, buf, NULL); + + if (!secp256k1_schnorrsig_real_verify(ctx, &rj, &s, &e, pk) + || !secp256k1_gej_has_quad_y_var(&rj) /* fails if rj is infinity */ + || !secp256k1_gej_eq_x_var(&rx, &rj)) { + return 0; + } + + return 1; +} + +/* Data that is used by the batch verification ecmult callback */ +typedef struct { + const secp256k1_context *ctx; + /* Seed for the random number generator */ + unsigned char chacha_seed[32]; + /* Caches randomizers generated by the PRNG which returns two randomizers per call. Caching + * avoids having to call the PRNG twice as often. The very first randomizer will be set to 1 and + * the PRNG is called at every odd indexed schnorrsig to fill the cache. */ + secp256k1_scalar randomizer_cache[2]; + /* Signature, message, public key tuples to verify */ + const secp256k1_schnorrsig *const *sig; + const unsigned char *const *msg32; + const secp256k1_pubkey *const *pk; + size_t n_sigs; +} secp256k1_schnorrsig_verify_ecmult_context; + +/* Callback function which is called by ecmult_multi in order to convert the ecmult_context + * consisting of signature, message and public key tuples into scalars and points. */ +static int secp256k1_schnorrsig_verify_batch_ecmult_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) { + secp256k1_schnorrsig_verify_ecmult_context *ecmult_context = (secp256k1_schnorrsig_verify_ecmult_context *) data; + + if (idx % 4 == 2) { + /* Every idx corresponds to a (scalar,point)-tuple. So this callback is called with 4 + * consecutive tuples before we need to call the RNG for new randomizers: + * (-randomizer_cache[0], R1) + * (-randomizer_cache[0]*e1, P1) + * (-randomizer_cache[1], R2) + * (-randomizer_cache[1]*e2, P2) */ + secp256k1_scalar_chacha20(&ecmult_context->randomizer_cache[0], &ecmult_context->randomizer_cache[1], ecmult_context->chacha_seed, idx / 4); + } + + /* R */ + if (idx % 2 == 0) { + secp256k1_fe rx; + *sc = ecmult_context->randomizer_cache[(idx / 2) % 2]; + if (!secp256k1_fe_set_b32(&rx, &ecmult_context->sig[idx / 2]->data[0])) { + return 0; + } + if (!secp256k1_ge_set_xquad(pt, &rx)) { + return 0; + } + /* eP */ + } else { + unsigned char buf[33]; + size_t buflen = sizeof(buf); + secp256k1_sha256 sha; + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, &ecmult_context->sig[idx / 2]->data[0], 32); + secp256k1_ec_pubkey_serialize(ecmult_context->ctx, buf, &buflen, ecmult_context->pk[idx / 2], SECP256K1_EC_COMPRESSED); + secp256k1_sha256_write(&sha, buf, buflen); + secp256k1_sha256_write(&sha, ecmult_context->msg32[idx / 2], 32); + secp256k1_sha256_finalize(&sha, buf); + + secp256k1_scalar_set_b32(sc, buf, NULL); + secp256k1_scalar_mul(sc, sc, &ecmult_context->randomizer_cache[(idx / 2) % 2]); + + if (!secp256k1_pubkey_load(ecmult_context->ctx, pt, ecmult_context->pk[idx / 2])) { + return 0; + } + } + return 1; +} + +/** Helper function for batch verification. Hashes signature verification data into the + * randomization seed and initializes ecmult_context. + * + * Returns 1 if the randomizer was successfully initialized. + * + * Args: ctx: a secp256k1 context object + * Out: ecmult_context: context for batch_ecmult_callback + * In/Out sha: an initialized sha256 object which hashes the schnorrsig input in order to get a + * seed for the randomizer PRNG + * In: sig: array of signatures, or NULL if there are no signatures + * msg32: array of messages, or NULL if there are no signatures + * pk: array of public keys, or NULL if there are no signatures + * n_sigs: number of signatures in above arrays (must be 0 if they are NULL) + */ +static int secp256k1_schnorrsig_verify_batch_init_randomizer(const secp256k1_context *ctx, secp256k1_schnorrsig_verify_ecmult_context *ecmult_context, secp256k1_sha256 *sha, const secp256k1_schnorrsig *const *sig, const unsigned char *const *msg32, const secp256k1_pubkey *const *pk, size_t n_sigs) { + size_t i; + + if (n_sigs > 0) { + ARG_CHECK(sig != NULL); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(pk != NULL); + } + + for (i = 0; i < n_sigs; i++) { + unsigned char buf[33]; + size_t buflen = sizeof(buf); + secp256k1_sha256_write(sha, sig[i]->data, 64); + secp256k1_sha256_write(sha, msg32[i], 32); + secp256k1_ec_pubkey_serialize(ctx, buf, &buflen, pk[i], SECP256K1_EC_COMPRESSED); + secp256k1_sha256_write(sha, buf, buflen); + } + ecmult_context->ctx = ctx; + ecmult_context->sig = sig; + ecmult_context->msg32 = msg32; + ecmult_context->pk = pk; + ecmult_context->n_sigs = n_sigs; + + return 1; +} + +/** Helper function for batch verification. Sums the s part of all signatures multiplied by their + * randomizer. + * + * Returns 1 if s is successfully summed. + * + * In/Out: s: the s part of the input sigs is added to this s argument + * In: chacha_seed: PRNG seed for computing randomizers + * sig: array of signatures, or NULL if there are no signatures + * n_sigs: number of signatures in above array (must be 0 if they are NULL) + */ +static int secp256k1_schnorrsig_verify_batch_sum_s(secp256k1_scalar *s, unsigned char *chacha_seed, const secp256k1_schnorrsig *const *sig, size_t n_sigs) { + secp256k1_scalar randomizer_cache[2]; + size_t i; + + secp256k1_scalar_set_int(&randomizer_cache[0], 1); + for (i = 0; i < n_sigs; i++) { + int overflow; + secp256k1_scalar term; + if (i % 2 == 1) { + secp256k1_scalar_chacha20(&randomizer_cache[0], &randomizer_cache[1], chacha_seed, i / 2); + } + + secp256k1_scalar_set_b32(&term, &sig[i]->data[32], &overflow); + if (overflow) { + return 0; + } + secp256k1_scalar_mul(&term, &term, &randomizer_cache[i % 2]); + secp256k1_scalar_add(s, s, &term); + } + return 1; +} + +/* schnorrsig batch verification. + * Seeds a random number generator with the inputs and derives a random number ai for every + * signature i. Fails if y-coordinate of any R is not a quadratic residue or if + * 0 != -(s1 + a2*s2 + ... + au*su)G + R1 + a2*R2 + ... + au*Ru + e1*P1 + (a2*e2)P2 + ... + (au*eu)Pu. */ +int secp256k1_schnorrsig_verify_batch(const secp256k1_context *ctx, secp256k1_scratch *scratch, const secp256k1_schnorrsig *const *sig, const unsigned char *const *msg32, const secp256k1_pubkey *const *pk, size_t n_sigs) { + secp256k1_schnorrsig_verify_ecmult_context ecmult_context; + secp256k1_sha256 sha; + secp256k1_scalar s; + secp256k1_gej rj; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(scratch != NULL); + /* Check that n_sigs is less than half of the maximum size_t value. This is necessary because + * the number of points given to ecmult_multi is 2*n_sigs. */ + ARG_CHECK(n_sigs <= SIZE_MAX / 2); + /* Check that n_sigs is less than 2^31 to ensure the same behavior of this function on 32-bit + * and 64-bit platforms. */ + ARG_CHECK(n_sigs < ((uint32_t)1 << 31)); + + secp256k1_sha256_initialize(&sha); + if (!secp256k1_schnorrsig_verify_batch_init_randomizer(ctx, &ecmult_context, &sha, sig, msg32, pk, n_sigs)) { + return 0; + } + secp256k1_sha256_finalize(&sha, ecmult_context.chacha_seed); + secp256k1_scalar_set_int(&ecmult_context.randomizer_cache[0], 1); + + secp256k1_scalar_clear(&s); + if (!secp256k1_schnorrsig_verify_batch_sum_s(&s, ecmult_context.chacha_seed, sig, n_sigs)) { + return 0; + } + secp256k1_scalar_negate(&s, &s); + + return secp256k1_ecmult_multi_var(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &rj, &s, secp256k1_schnorrsig_verify_batch_ecmult_callback, (void *) &ecmult_context, 2 * n_sigs) + && secp256k1_gej_is_infinity(&rj); +} + +#endif diff --git a/src/secp256k1/src/modules/schnorrsig/tests_impl.h b/src/secp256k1/src/modules/schnorrsig/tests_impl.h new file mode 100644 index 000000000000..2de43af1e33b --- /dev/null +++ b/src/secp256k1/src/modules/schnorrsig/tests_impl.h @@ -0,0 +1,721 @@ +/********************************************************************** + * Copyright (c) 2018 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_MODULE_SCHNORRSIG_TESTS_ +#define _SECP256K1_MODULE_SCHNORRSIG_TESTS_ + +#include "secp256k1_schnorrsig.h" + +void test_schnorrsig_serialize(void) { + secp256k1_schnorrsig sig; + unsigned char in[64]; + unsigned char out[64]; + + memset(in, 0x12, 64); + CHECK(secp256k1_schnorrsig_parse(ctx, &sig, in)); + CHECK(secp256k1_schnorrsig_serialize(ctx, out, &sig)); + CHECK(memcmp(in, out, 64) == 0); +} + +void test_schnorrsig_api(secp256k1_scratch_space *scratch) { + unsigned char sk1[32]; + unsigned char sk2[32]; + unsigned char sk3[32]; + unsigned char msg[32]; + unsigned char sig64[64]; + secp256k1_pubkey pk[3]; + secp256k1_schnorrsig sig; + const secp256k1_schnorrsig *sigptr = &sig; + const unsigned char *msgptr = msg; + const secp256k1_pubkey *pkptr = &pk[0]; + + /** setup **/ + secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + int ecount; + + secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount); + + secp256k1_rand256(sk1); + secp256k1_rand256(sk2); + secp256k1_rand256(sk3); + secp256k1_rand256(msg); + CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk1) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pk[1], sk2) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pk[2], sk3) == 1); + + /** main test body **/ + ecount = 0; + CHECK(secp256k1_schnorrsig_sign(none, &sig, msg, sk1, NULL, NULL) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_schnorrsig_sign(vrfy, &sig, msg, sk1, NULL, NULL) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_schnorrsig_sign(sign, &sig, msg, sk1, NULL, NULL) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_schnorrsig_sign(sign, NULL, msg, sk1, NULL, NULL) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_schnorrsig_sign(sign, &sig, NULL, sk1, NULL, NULL) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_schnorrsig_sign(sign, &sig, msg, NULL, NULL, NULL) == 0); + CHECK(ecount == 5); + + ecount = 0; + CHECK(secp256k1_schnorrsig_serialize(none, sig64, &sig) == 1); + CHECK(ecount == 0); + CHECK(secp256k1_schnorrsig_serialize(none, NULL, &sig) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_schnorrsig_serialize(none, sig64, NULL) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_schnorrsig_parse(none, &sig, sig64) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_schnorrsig_parse(none, NULL, sig64) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_schnorrsig_parse(none, &sig, NULL) == 0); + CHECK(ecount == 4); + + ecount = 0; + CHECK(secp256k1_schnorrsig_verify(none, &sig, msg, &pk[0]) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_schnorrsig_verify(sign, &sig, msg, &pk[0]) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_schnorrsig_verify(vrfy, &sig, msg, &pk[0]) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_schnorrsig_verify(vrfy, NULL, msg, &pk[0]) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_schnorrsig_verify(vrfy, &sig, NULL, &pk[0]) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_schnorrsig_verify(vrfy, &sig, msg, NULL) == 0); + CHECK(ecount == 5); + + ecount = 0; + CHECK(secp256k1_schnorrsig_verify_batch(none, scratch, &sigptr, &msgptr, &pkptr, 1) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_schnorrsig_verify_batch(sign, scratch, &sigptr, &msgptr, &pkptr, 1) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, &sigptr, &msgptr, &pkptr, 1) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, NULL, NULL, NULL, 0) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, NULL, &msgptr, &pkptr, 1) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, &sigptr, NULL, &pkptr, 1) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, &sigptr, &msgptr, NULL, 1) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, &sigptr, &msgptr, &pkptr, (size_t)1 << (sizeof(size_t)*8-1)) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, &sigptr, &msgptr, &pkptr, (uint32_t)1 << 31) == 0); + CHECK(ecount == 7); + + secp256k1_context_destroy(none); + secp256k1_context_destroy(sign); + secp256k1_context_destroy(vrfy); + secp256k1_context_destroy(both); +} + +/* Helper function for schnorrsig_bip_vectors + * Signs the message and checks that it's the same as expected_sig. */ +void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, const unsigned char *msg, const unsigned char *expected_sig) { + secp256k1_schnorrsig sig; + unsigned char serialized_sig[64]; + secp256k1_pubkey pk; + + CHECK(secp256k1_schnorrsig_sign(ctx, &sig, msg, sk, NULL, NULL)); + CHECK(secp256k1_schnorrsig_serialize(ctx, serialized_sig, &sig)); + CHECK(memcmp(serialized_sig, expected_sig, 64) == 0); + + CHECK(secp256k1_ec_pubkey_parse(ctx, &pk, pk_serialized, 33)); + CHECK(secp256k1_schnorrsig_verify(ctx, &sig, msg, &pk)); +} + +/* Helper function for schnorrsig_bip_vectors + * Checks that both verify and verify_batch return the same value as expected. */ +void test_schnorrsig_bip_vectors_check_verify(secp256k1_scratch_space *scratch, const unsigned char *pk_serialized, const unsigned char *msg32, const unsigned char *sig_serialized, int expected) { + const unsigned char *msg_arr[1]; + const secp256k1_schnorrsig *sig_arr[1]; + const secp256k1_pubkey *pk_arr[1]; + secp256k1_pubkey pk; + secp256k1_schnorrsig sig; + + CHECK(secp256k1_ec_pubkey_parse(ctx, &pk, pk_serialized, 33)); + CHECK(secp256k1_schnorrsig_parse(ctx, &sig, sig_serialized)); + + sig_arr[0] = &sig; + msg_arr[0] = msg32; + pk_arr[0] = &pk; + + CHECK(expected == secp256k1_schnorrsig_verify(ctx, &sig, msg32, &pk)); + CHECK(expected == secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 1)); +} + +/* Test vectors according to BIP-schnorr + * (https://github.com/sipa/bips/blob/7f6a73e53c8bbcf2d008ea0546f76433e22094a8/bip-schnorr/test-vectors.csv). + */ +void test_schnorrsig_bip_vectors(secp256k1_scratch_space *scratch) { + { + /* Test vector 1 */ + const unsigned char sk1[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + }; + const unsigned char pk1[33] = { + 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, + 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, + 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, + 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, + 0x98 + }; + const unsigned char msg1[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const unsigned char sig1[64] = { + 0x78, 0x7A, 0x84, 0x8E, 0x71, 0x04, 0x3D, 0x28, + 0x0C, 0x50, 0x47, 0x0E, 0x8E, 0x15, 0x32, 0xB2, + 0xDD, 0x5D, 0x20, 0xEE, 0x91, 0x2A, 0x45, 0xDB, + 0xDD, 0x2B, 0xD1, 0xDF, 0xBF, 0x18, 0x7E, 0xF6, + 0x70, 0x31, 0xA9, 0x88, 0x31, 0x85, 0x9D, 0xC3, + 0x4D, 0xFF, 0xEE, 0xDD, 0xA8, 0x68, 0x31, 0x84, + 0x2C, 0xCD, 0x00, 0x79, 0xE1, 0xF9, 0x2A, 0xF1, + 0x77, 0xF7, 0xF2, 0x2C, 0xC1, 0xDC, 0xED, 0x05 + }; + test_schnorrsig_bip_vectors_check_signing(sk1, pk1, msg1, sig1); + test_schnorrsig_bip_vectors_check_verify(scratch, pk1, msg1, sig1, 1); + } + { + /* Test vector 2 */ + const unsigned char sk2[32] = { + 0xB7, 0xE1, 0x51, 0x62, 0x8A, 0xED, 0x2A, 0x6A, + 0xBF, 0x71, 0x58, 0x80, 0x9C, 0xF4, 0xF3, 0xC7, + 0x62, 0xE7, 0x16, 0x0F, 0x38, 0xB4, 0xDA, 0x56, + 0xA7, 0x84, 0xD9, 0x04, 0x51, 0x90, 0xCF, 0xEF + }; + const unsigned char pk2[33] = { + 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, + 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, + 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, + 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, + 0x59 + }; + const unsigned char msg2[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig2[64] = { + 0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, + 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, + 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, + 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, + 0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, + 0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, + 0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, + 0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD + }; + test_schnorrsig_bip_vectors_check_signing(sk2, pk2, msg2, sig2); + test_schnorrsig_bip_vectors_check_verify(scratch, pk2, msg2, sig2, 1); + } + { + /* Test vector 3 */ + const unsigned char sk3[32] = { + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x14, 0xE5, 0xC7 + }; + const unsigned char pk3[33] = { + 0x03, 0xFA, 0xC2, 0x11, 0x4C, 0x2F, 0xBB, 0x09, + 0x15, 0x27, 0xEB, 0x7C, 0x64, 0xEC, 0xB1, 0x1F, + 0x80, 0x21, 0xCB, 0x45, 0xE8, 0xE7, 0x80, 0x9D, + 0x3C, 0x09, 0x38, 0xE4, 0xB8, 0xC0, 0xE5, 0xF8, + 0x4B + }; + const unsigned char msg3[32] = { + 0x5E, 0x2D, 0x58, 0xD8, 0xB3, 0xBC, 0xDF, 0x1A, + 0xBA, 0xDE, 0xC7, 0x82, 0x90, 0x54, 0xF9, 0x0D, + 0xDA, 0x98, 0x05, 0xAA, 0xB5, 0x6C, 0x77, 0x33, + 0x30, 0x24, 0xB9, 0xD0, 0xA5, 0x08, 0xB7, 0x5C + }; + const unsigned char sig3[64] = { + 0x00, 0xDA, 0x9B, 0x08, 0x17, 0x2A, 0x9B, 0x6F, + 0x04, 0x66, 0xA2, 0xDE, 0xFD, 0x81, 0x7F, 0x2D, + 0x7A, 0xB4, 0x37, 0xE0, 0xD2, 0x53, 0xCB, 0x53, + 0x95, 0xA9, 0x63, 0x86, 0x6B, 0x35, 0x74, 0xBE, + 0x00, 0x88, 0x03, 0x71, 0xD0, 0x17, 0x66, 0x93, + 0x5B, 0x92, 0xD2, 0xAB, 0x4C, 0xD5, 0xC8, 0xA2, + 0xA5, 0x83, 0x7E, 0xC5, 0x7F, 0xED, 0x76, 0x60, + 0x77, 0x3A, 0x05, 0xF0, 0xDE, 0x14, 0x23, 0x80 + }; + test_schnorrsig_bip_vectors_check_signing(sk3, pk3, msg3, sig3); + test_schnorrsig_bip_vectors_check_verify(scratch, pk3, msg3, sig3, 1); + } + { + /* Test vector 4 */ + const unsigned char pk4[33] = { + 0x03, 0xDE, 0xFD, 0xEA, 0x4C, 0xDB, 0x67, 0x77, + 0x50, 0xA4, 0x20, 0xFE, 0xE8, 0x07, 0xEA, 0xCF, + 0x21, 0xEB, 0x98, 0x98, 0xAE, 0x79, 0xB9, 0x76, + 0x87, 0x66, 0xE4, 0xFA, 0xA0, 0x4A, 0x2D, 0x4A, + 0x34 + }; + const unsigned char msg4[32] = { + 0x4D, 0xF3, 0xC3, 0xF6, 0x8F, 0xCC, 0x83, 0xB2, + 0x7E, 0x9D, 0x42, 0xC9, 0x04, 0x31, 0xA7, 0x24, + 0x99, 0xF1, 0x78, 0x75, 0xC8, 0x1A, 0x59, 0x9B, + 0x56, 0x6C, 0x98, 0x89, 0xB9, 0x69, 0x67, 0x03 + }; + const unsigned char sig4[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3B, 0x78, 0xCE, 0x56, 0x3F, + 0x89, 0xA0, 0xED, 0x94, 0x14, 0xF5, 0xAA, 0x28, + 0xAD, 0x0D, 0x96, 0xD6, 0x79, 0x5F, 0x9C, 0x63, + 0x02, 0xA8, 0xDC, 0x32, 0xE6, 0x4E, 0x86, 0xA3, + 0x33, 0xF2, 0x0E, 0xF5, 0x6E, 0xAC, 0x9B, 0xA3, + 0x0B, 0x72, 0x46, 0xD6, 0xD2, 0x5E, 0x22, 0xAD, + 0xB8, 0xC6, 0xBE, 0x1A, 0xEB, 0x08, 0xD4, 0x9D + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk4, msg4, sig4, 1); + } + { + /* Test vector 5 */ + const unsigned char pk5[33] = { + 0x03, 0x1B, 0x84, 0xC5, 0x56, 0x7B, 0x12, 0x64, + 0x40, 0x99, 0x5D, 0x3E, 0xD5, 0xAA, 0xBA, 0x05, + 0x65, 0xD7, 0x1E, 0x18, 0x34, 0x60, 0x48, 0x19, + 0xFF, 0x9C, 0x17, 0xF5, 0xE9, 0xD5, 0xDD, 0x07, + 0x8F + }; + const unsigned char msg5[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const unsigned char sig5[64] = { + 0x52, 0x81, 0x85, 0x79, 0xAC, 0xA5, 0x97, 0x67, + 0xE3, 0x29, 0x1D, 0x91, 0xB7, 0x6B, 0x63, 0x7B, + 0xEF, 0x06, 0x20, 0x83, 0x28, 0x49, 0x92, 0xF2, + 0xD9, 0x5F, 0x56, 0x4C, 0xA6, 0xCB, 0x4E, 0x35, + 0x30, 0xB1, 0xDA, 0x84, 0x9C, 0x8E, 0x83, 0x04, + 0xAD, 0xC0, 0xCF, 0xE8, 0x70, 0x66, 0x03, 0x34, + 0xB3, 0xCF, 0xC1, 0x8E, 0x82, 0x5E, 0xF1, 0xDB, + 0x34, 0xCF, 0xAE, 0x3D, 0xFC, 0x5D, 0x81, 0x87 + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk5, msg5, sig5, 1); + } + { + /* Test vector 6 */ + const unsigned char pk6[33] = { + 0x03, 0xFA, 0xC2, 0x11, 0x4C, 0x2F, 0xBB, 0x09, + 0x15, 0x27, 0xEB, 0x7C, 0x64, 0xEC, 0xB1, 0x1F, + 0x80, 0x21, 0xCB, 0x45, 0xE8, 0xE7, 0x80, 0x9D, + 0x3C, 0x09, 0x38, 0xE4, 0xB8, 0xC0, 0xE5, 0xF8, + 0x4B + }; + const unsigned char msg6[32] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; + const unsigned char sig6[64] = { + 0x57, 0x0D, 0xD4, 0xCA, 0x83, 0xD4, 0xE6, 0x31, + 0x7B, 0x8E, 0xE6, 0xBA, 0xE8, 0x34, 0x67, 0xA1, + 0xBF, 0x41, 0x9D, 0x07, 0x67, 0x12, 0x2D, 0xE4, + 0x09, 0x39, 0x44, 0x14, 0xB0, 0x50, 0x80, 0xDC, + 0xE9, 0xEE, 0x5F, 0x23, 0x7C, 0xBD, 0x10, 0x8E, + 0xAB, 0xAE, 0x1E, 0x37, 0x75, 0x9A, 0xE4, 0x7F, + 0x8E, 0x42, 0x03, 0xDA, 0x35, 0x32, 0xEB, 0x28, + 0xDB, 0x86, 0x0F, 0x33, 0xD6, 0x2D, 0x49, 0xBD + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk6, msg6, sig6, 1); + } + { + /* Test vector 7 */ + const unsigned char pk7[33] = { + 0x03, 0xEE, 0xFD, 0xEA, 0x4C, 0xDB, 0x67, 0x77, + 0x50, 0xA4, 0x20, 0xFE, 0xE8, 0x07, 0xEA, 0xCF, + 0x21, 0xEB, 0x98, 0x98, 0xAE, 0x79, 0xB9, 0x76, + 0x87, 0x66, 0xE4, 0xFA, 0xA0, 0x4A, 0x2D, 0x4A, + 0x34 + }; + secp256k1_pubkey pk7_parsed; + /* No need to check the signature of the test vector as parsing the pubkey already fails */ + CHECK(!secp256k1_ec_pubkey_parse(ctx, &pk7_parsed, pk7, 33)); + } + { + /* Test vector 8 */ + const unsigned char pk8[33] = { + 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, + 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, + 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, + 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, + 0x59 + }; + const unsigned char msg8[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig8[64] = { + 0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, + 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, + 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, + 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, + 0xFA, 0x16, 0xAE, 0xE0, 0x66, 0x09, 0x28, 0x0A, + 0x19, 0xB6, 0x7A, 0x24, 0xE1, 0x97, 0x7E, 0x46, + 0x97, 0x71, 0x2B, 0x5F, 0xD2, 0x94, 0x39, 0x14, + 0xEC, 0xD5, 0xF7, 0x30, 0x90, 0x1B, 0x4A, 0xB7 + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk8, msg8, sig8, 0); + } + { + /* Test vector 9 */ + const unsigned char pk9[33] = { + 0x03, 0xFA, 0xC2, 0x11, 0x4C, 0x2F, 0xBB, 0x09, + 0x15, 0x27, 0xEB, 0x7C, 0x64, 0xEC, 0xB1, 0x1F, + 0x80, 0x21, 0xCB, 0x45, 0xE8, 0xE7, 0x80, 0x9D, + 0x3C, 0x09, 0x38, 0xE4, 0xB8, 0xC0, 0xE5, 0xF8, + 0x4B + }; + const unsigned char msg9[32] = { + 0x5E, 0x2D, 0x58, 0xD8, 0xB3, 0xBC, 0xDF, 0x1A, + 0xBA, 0xDE, 0xC7, 0x82, 0x90, 0x54, 0xF9, 0x0D, + 0xDA, 0x98, 0x05, 0xAA, 0xB5, 0x6C, 0x77, 0x33, + 0x30, 0x24, 0xB9, 0xD0, 0xA5, 0x08, 0xB7, 0x5C + }; + const unsigned char sig9[64] = { + 0x00, 0xDA, 0x9B, 0x08, 0x17, 0x2A, 0x9B, 0x6F, + 0x04, 0x66, 0xA2, 0xDE, 0xFD, 0x81, 0x7F, 0x2D, + 0x7A, 0xB4, 0x37, 0xE0, 0xD2, 0x53, 0xCB, 0x53, + 0x95, 0xA9, 0x63, 0x86, 0x6B, 0x35, 0x74, 0xBE, + 0xD0, 0x92, 0xF9, 0xD8, 0x60, 0xF1, 0x77, 0x6A, + 0x1F, 0x74, 0x12, 0xAD, 0x8A, 0x1E, 0xB5, 0x0D, + 0xAC, 0xCC, 0x22, 0x2B, 0xC8, 0xC0, 0xE2, 0x6B, + 0x20, 0x56, 0xDF, 0x2F, 0x27, 0x3E, 0xFD, 0xEC + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk9, msg9, sig9, 0); + } + { + /* Test vector 10 */ + const unsigned char pk10[33] = { + 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, + 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, + 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, + 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, + 0x98 + }; + const unsigned char msg10[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const unsigned char sig10[64] = { + 0x78, 0x7A, 0x84, 0x8E, 0x71, 0x04, 0x3D, 0x28, + 0x0C, 0x50, 0x47, 0x0E, 0x8E, 0x15, 0x32, 0xB2, + 0xDD, 0x5D, 0x20, 0xEE, 0x91, 0x2A, 0x45, 0xDB, + 0xDD, 0x2B, 0xD1, 0xDF, 0xBF, 0x18, 0x7E, 0xF6, + 0x8F, 0xCE, 0x56, 0x77, 0xCE, 0x7A, 0x62, 0x3C, + 0xB2, 0x00, 0x11, 0x22, 0x57, 0x97, 0xCE, 0x7A, + 0x8D, 0xE1, 0xDC, 0x6C, 0xCD, 0x4F, 0x75, 0x4A, + 0x47, 0xDA, 0x6C, 0x60, 0x0E, 0x59, 0x54, 0x3C + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk10, msg10, sig10, 0); + } + { + /* Test vector 11 */ + const unsigned char pk11[33] = { + 0x03, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, + 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, + 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, + 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, + 0x59 + }; + const unsigned char msg11[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig11[64] = { + 0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, + 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, + 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, + 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, + 0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, + 0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, + 0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, + 0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk11, msg11, sig11, 0); + } + { + /* Test vector 12 */ + const unsigned char pk12[33] = { + 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, + 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, + 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, + 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, + 0x59 + }; + const unsigned char msg12[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig12[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9E, 0x9D, 0x01, 0xAF, 0x98, 0x8B, 0x5C, 0xED, + 0xCE, 0x47, 0x22, 0x1B, 0xFA, 0x9B, 0x22, 0x27, + 0x21, 0xF3, 0xFA, 0x40, 0x89, 0x15, 0x44, 0x4A, + 0x4B, 0x48, 0x90, 0x21, 0xDB, 0x55, 0x77, 0x5F + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk12, msg12, sig12, 0); + } + { + /* Test vector 13 */ + const unsigned char pk13[33] = { + 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, + 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, + 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, + 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, + 0x59 + }; + const unsigned char msg13[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig13[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xD3, 0x7D, 0xDF, 0x02, 0x54, 0x35, 0x18, 0x36, + 0xD8, 0x4B, 0x1B, 0xD6, 0xA7, 0x95, 0xFD, 0x5D, + 0x52, 0x30, 0x48, 0xF2, 0x98, 0xC4, 0x21, 0x4D, + 0x18, 0x7F, 0xE4, 0x89, 0x29, 0x47, 0xF7, 0x28 + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk13, msg13, sig13, 0); + } + { + /* Test vector 14 */ + const unsigned char pk14[33] = { + 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, + 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, + 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, + 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, + 0x59 + }; + const unsigned char msg14[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x14, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig14[64] = { + 0x4A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, + 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, + 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, + 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, + 0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, + 0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, + 0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, + 0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk14, msg14, sig14, 0); + } + { + /* Test vector 15 */ + const unsigned char pk15[33] = { + 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, + 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, + 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, + 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, + 0x59 + }; + const unsigned char msg15[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig15[64] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x2F, + 0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, + 0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, + 0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, + 0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk15, msg15, sig15, 0); + } + { + /* Test vector 16 */ + const unsigned char pk16[33] = { + 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, + 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, + 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, + 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, + 0x59 + }; + const unsigned char msg16[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig16[64] = { + 0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, + 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, + 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, + 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, + 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, + 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk16, msg16, sig16, 0); + } +} + +/* Nonce function that returns constant 0 */ +static int nonce_function_failing(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + (void) msg32; + (void) key32; + (void) algo16; + (void) data; + (void) counter; + (void) nonce32; + return 0; +} + +/* Nonce function that sets nonce to 0 */ +static int nonce_function_0(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + (void) msg32; + (void) key32; + (void) algo16; + (void) data; + (void) counter; + + memset(nonce32, 0, 32); + return 1; +} + +void test_schnorrsig_sign(void) { + unsigned char sk[32]; + const unsigned char msg[32] = "this is a msg for a schnorrsig.."; + secp256k1_schnorrsig sig; + + memset(sk, 23, sizeof(sk)); + CHECK(secp256k1_schnorrsig_sign(ctx, &sig, msg, sk, NULL, NULL) == 1); + + /* Overflowing secret key */ + memset(sk, 0xFF, sizeof(sk)); + CHECK(secp256k1_schnorrsig_sign(ctx, &sig, msg, sk, NULL, NULL) == 0); + memset(sk, 23, sizeof(sk)); + + CHECK(secp256k1_schnorrsig_sign(ctx, &sig, msg, sk, nonce_function_failing, NULL) == 0); + CHECK(secp256k1_schnorrsig_sign(ctx, &sig, msg, sk, nonce_function_0, NULL) == 0); +} + +#define N_SIGS 200 +/* Creates N_SIGS valid signatures and verifies them with verify and verify_batch. Then flips some + * bits and checks that verification now fails. */ +void test_schnorrsig_sign_verify(secp256k1_scratch_space *scratch) { + const unsigned char sk[32] = "shhhhhhhh! this key is a secret."; + unsigned char msg[N_SIGS][32]; + secp256k1_schnorrsig sig[N_SIGS]; + size_t i; + const secp256k1_schnorrsig *sig_arr[N_SIGS]; + const unsigned char *msg_arr[N_SIGS]; + const secp256k1_pubkey *pk_arr[N_SIGS]; + secp256k1_pubkey pk; + + CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk)); + + CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, NULL, NULL, NULL, 0)); + + for (i = 0; i < N_SIGS; i++) { + secp256k1_rand256(msg[i]); + CHECK(secp256k1_schnorrsig_sign(ctx, &sig[i], msg[i], sk, NULL, NULL)); + CHECK(secp256k1_schnorrsig_verify(ctx, &sig[i], msg[i], &pk)); + sig_arr[i] = &sig[i]; + msg_arr[i] = msg[i]; + pk_arr[i] = &pk; + } + + CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 1)); + CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 2)); + CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4)); + CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, N_SIGS)); + + { + /* Flip a few bits in the signature and in the message and check that + * verify and verify_batch fail */ + size_t sig_idx = secp256k1_rand_int(4); + size_t byte_idx = secp256k1_rand_int(32); + unsigned char xorbyte = secp256k1_rand_int(254)+1; + sig[sig_idx].data[byte_idx] ^= xorbyte; + CHECK(!secp256k1_schnorrsig_verify(ctx, &sig[sig_idx], msg[sig_idx], &pk)); + CHECK(!secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4)); + sig[sig_idx].data[byte_idx] ^= xorbyte; + + byte_idx = secp256k1_rand_int(32); + sig[sig_idx].data[32+byte_idx] ^= xorbyte; + CHECK(!secp256k1_schnorrsig_verify(ctx, &sig[sig_idx], msg[sig_idx], &pk)); + CHECK(!secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4)); + sig[sig_idx].data[32+byte_idx] ^= xorbyte; + + byte_idx = secp256k1_rand_int(32); + msg[sig_idx][byte_idx] ^= xorbyte; + CHECK(!secp256k1_schnorrsig_verify(ctx, &sig[sig_idx], msg[sig_idx], &pk)); + CHECK(!secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4)); + msg[sig_idx][byte_idx] ^= xorbyte; + + /* Check that above bitflips have been reversed correctly */ + CHECK(secp256k1_schnorrsig_verify(ctx, &sig[sig_idx], msg[sig_idx], &pk)); + CHECK(secp256k1_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4)); + } +} +#undef N_SIGS + +void run_schnorrsig_tests(void) { + secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(ctx, 1024 * 1024); + + test_schnorrsig_serialize(); + test_schnorrsig_api(scratch); + test_schnorrsig_bip_vectors(scratch); + test_schnorrsig_sign(); + test_schnorrsig_sign_verify(scratch); + + secp256k1_scratch_space_destroy(ctx, scratch); +} + +#endif diff --git a/src/secp256k1/src/scalar.h b/src/secp256k1/src/scalar.h index 59304cb66e90..640693a5e32e 100644 --- a/src/secp256k1/src/scalar.h +++ b/src/secp256k1/src/scalar.h @@ -103,4 +103,7 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar /** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */ static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift); +/** Generate two scalars from a 32-byte seed and an integer using the chacha20 stream cipher */ +static void secp256k1_scalar_chacha20(secp256k1_scalar *r1, secp256k1_scalar *r2, const unsigned char *seed, uint64_t idx); + #endif /* SECP256K1_SCALAR_H */ diff --git a/src/secp256k1/src/scalar_4x64_impl.h b/src/secp256k1/src/scalar_4x64_impl.h index d378335d996f..268cc68d60fc 100644 --- a/src/secp256k1/src/scalar_4x64_impl.h +++ b/src/secp256k1/src/scalar_4x64_impl.h @@ -7,6 +7,9 @@ #ifndef SECP256K1_SCALAR_REPR_IMPL_H #define SECP256K1_SCALAR_REPR_IMPL_H +#include "scalar.h" +#include + /* Limbs of the secp256k1 order. */ #define SECP256K1_N_0 ((uint64_t)0xBFD25E8CD0364141ULL) #define SECP256K1_N_1 ((uint64_t)0xBAAEDCE6AF48A03BULL) @@ -946,4 +949,91 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1); } +#define ROTL32(x,n) ((x) << (n) | (x) >> (32-(n))) +#define QUARTERROUND(a,b,c,d) \ + a += b; d = ROTL32(d ^ a, 16); \ + c += d; b = ROTL32(b ^ c, 12); \ + a += b; d = ROTL32(d ^ a, 8); \ + c += d; b = ROTL32(b ^ c, 7); + +#ifdef WORDS_BIGENDIAN +#define LE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) +#else +#define LE32(p) (p) +#endif + +static void secp256k1_scalar_chacha20(secp256k1_scalar *r1, secp256k1_scalar *r2, const unsigned char *seed, uint64_t idx) { + size_t n; + size_t over_count = 0; + uint32_t seed32[8]; + uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + int over1, over2; + + memcpy((void *) seed32, (const void *) seed, 32); + do { + x0 = 0x61707865; + x1 = 0x3320646e; + x2 = 0x79622d32; + x3 = 0x6b206574; + x4 = LE32(seed32[0]); + x5 = LE32(seed32[1]); + x6 = LE32(seed32[2]); + x7 = LE32(seed32[3]); + x8 = LE32(seed32[4]); + x9 = LE32(seed32[5]); + x10 = LE32(seed32[6]); + x11 = LE32(seed32[7]); + x12 = idx; + x13 = idx >> 32; + x14 = 0; + x15 = over_count; + + n = 10; + while (n--) { + QUARTERROUND(x0, x4, x8,x12) + QUARTERROUND(x1, x5, x9,x13) + QUARTERROUND(x2, x6,x10,x14) + QUARTERROUND(x3, x7,x11,x15) + QUARTERROUND(x0, x5,x10,x15) + QUARTERROUND(x1, x6,x11,x12) + QUARTERROUND(x2, x7, x8,x13) + QUARTERROUND(x3, x4, x9,x14) + } + + x0 += 0x61707865; + x1 += 0x3320646e; + x2 += 0x79622d32; + x3 += 0x6b206574; + x4 += LE32(seed32[0]); + x5 += LE32(seed32[1]); + x6 += LE32(seed32[2]); + x7 += LE32(seed32[3]); + x8 += LE32(seed32[4]); + x9 += LE32(seed32[5]); + x10 += LE32(seed32[6]); + x11 += LE32(seed32[7]); + x12 += idx; + x13 += idx >> 32; + x14 += 0; + x15 += over_count; + + r1->d[3] = (((uint64_t) x0) << 32) | x1; + r1->d[2] = (((uint64_t) x2) << 32) | x3; + r1->d[1] = (((uint64_t) x4) << 32) | x5; + r1->d[0] = (((uint64_t) x6) << 32) | x7; + r2->d[3] = (((uint64_t) x8) << 32) | x9; + r2->d[2] = (((uint64_t) x10) << 32) | x11; + r2->d[1] = (((uint64_t) x12) << 32) | x13; + r2->d[0] = (((uint64_t) x14) << 32) | x15; + + over1 = secp256k1_scalar_check_overflow(r1); + over2 = secp256k1_scalar_check_overflow(r2); + over_count++; + } while (over1 | over2); +} + +#undef ROTL32 +#undef QUARTERROUND +#undef LE32 + #endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/src/secp256k1/src/scalar_8x32_impl.h b/src/secp256k1/src/scalar_8x32_impl.h index 4f9ed61feaec..a9a934c43c48 100644 --- a/src/secp256k1/src/scalar_8x32_impl.h +++ b/src/secp256k1/src/scalar_8x32_impl.h @@ -7,6 +7,8 @@ #ifndef SECP256K1_SCALAR_REPR_IMPL_H #define SECP256K1_SCALAR_REPR_IMPL_H +#include + /* Limbs of the secp256k1 order. */ #define SECP256K1_N_0 ((uint32_t)0xD0364141UL) #define SECP256K1_N_1 ((uint32_t)0xBFD25E8CUL) @@ -718,4 +720,99 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1); } +#define ROTL32(x,n) ((x) << (n) | (x) >> (32-(n))) +#define QUARTERROUND(a,b,c,d) \ + a += b; d = ROTL32(d ^ a, 16); \ + c += d; b = ROTL32(b ^ c, 12); \ + a += b; d = ROTL32(d ^ a, 8); \ + c += d; b = ROTL32(b ^ c, 7); + +#ifdef WORDS_BIGENDIAN +#define LE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) +#else +#define LE32(p) (p) +#endif + +static void secp256k1_scalar_chacha20(secp256k1_scalar *r1, secp256k1_scalar *r2, const unsigned char *seed, uint64_t idx) { + size_t n; + size_t over_count = 0; + uint32_t seed32[8]; + uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + int over1, over2; + + memcpy((void *) seed32, (const void *) seed, 32); + do { + x0 = 0x61707865; + x1 = 0x3320646e; + x2 = 0x79622d32; + x3 = 0x6b206574; + x4 = LE32(seed32[0]); + x5 = LE32(seed32[1]); + x6 = LE32(seed32[2]); + x7 = LE32(seed32[3]); + x8 = LE32(seed32[4]); + x9 = LE32(seed32[5]); + x10 = LE32(seed32[6]); + x11 = LE32(seed32[7]); + x12 = idx; + x13 = idx >> 32; + x14 = 0; + x15 = over_count; + + n = 10; + while (n--) { + QUARTERROUND(x0, x4, x8,x12) + QUARTERROUND(x1, x5, x9,x13) + QUARTERROUND(x2, x6,x10,x14) + QUARTERROUND(x3, x7,x11,x15) + QUARTERROUND(x0, x5,x10,x15) + QUARTERROUND(x1, x6,x11,x12) + QUARTERROUND(x2, x7, x8,x13) + QUARTERROUND(x3, x4, x9,x14) + } + + x0 += 0x61707865; + x1 += 0x3320646e; + x2 += 0x79622d32; + x3 += 0x6b206574; + x4 += LE32(seed32[0]); + x5 += LE32(seed32[1]); + x6 += LE32(seed32[2]); + x7 += LE32(seed32[3]); + x8 += LE32(seed32[4]); + x9 += LE32(seed32[5]); + x10 += LE32(seed32[6]); + x11 += LE32(seed32[7]); + x12 += idx; + x13 += idx >> 32; + x14 += 0; + x15 += over_count; + + r1->d[7] = x0; + r1->d[6] = x1; + r1->d[5] = x2; + r1->d[4] = x3; + r1->d[3] = x4; + r1->d[2] = x5; + r1->d[1] = x6; + r1->d[0] = x7; + r2->d[7] = x8; + r2->d[6] = x9; + r2->d[5] = x10; + r2->d[4] = x11; + r2->d[3] = x12; + r2->d[2] = x13; + r2->d[1] = x14; + r2->d[0] = x15; + + over1 = secp256k1_scalar_check_overflow(r1); + over2 = secp256k1_scalar_check_overflow(r2); + over_count++; + } while (over1 | over2); +} + +#undef ROTL32 +#undef QUARTERROUND +#undef LE32 + #endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/src/secp256k1/src/scalar_low_impl.h b/src/secp256k1/src/scalar_low_impl.h index c80e70c5a2ad..88e52d803120 100644 --- a/src/secp256k1/src/scalar_low_impl.h +++ b/src/secp256k1/src/scalar_low_impl.h @@ -111,4 +111,9 @@ SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const return *a == *b; } +SECP256K1_INLINE static void secp256k1_scalar_chacha20(secp256k1_scalar *r1, secp256k1_scalar *r2, const unsigned char *seed, uint64_t n) { + *r1 = (seed[0] + n) % EXHAUSTIVE_TEST_ORDER; + *r2 = (seed[1] + n) % EXHAUSTIVE_TEST_ORDER; +} + #endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/src/secp256k1/src/scratch.h b/src/secp256k1/src/scratch.h index fef377af0d94..77b35d126bbe 100644 --- a/src/secp256k1/src/scratch.h +++ b/src/secp256k1/src/scratch.h @@ -7,33 +7,36 @@ #ifndef _SECP256K1_SCRATCH_ #define _SECP256K1_SCRATCH_ -#define SECP256K1_SCRATCH_MAX_FRAMES 5 - /* The typedef is used internally; the struct name is used in the public API * (where it is exposed as a different typedef) */ typedef struct secp256k1_scratch_space_struct { - void *data[SECP256K1_SCRATCH_MAX_FRAMES]; - size_t offset[SECP256K1_SCRATCH_MAX_FRAMES]; - size_t frame_size[SECP256K1_SCRATCH_MAX_FRAMES]; - size_t frame; + /** guard against interpreting this object as other types */ + unsigned char magic[8]; + /** actual allocated data */ + void *data; + /** amount that has been allocated (i.e. `data + offset` is the next + * available pointer) */ + size_t alloc_size; + /** maximum size available to allocate */ size_t max_size; - const secp256k1_callback* error_callback; } secp256k1_scratch; static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t max_size); -static void secp256k1_scratch_destroy(secp256k1_scratch* scratch); +static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch); -/** Attempts to allocate a new stack frame with `n` available bytes. Returns 1 on success, 0 on failure */ -static int secp256k1_scratch_allocate_frame(secp256k1_scratch* scratch, size_t n, size_t objects); +/** Returns an opaque object used to "checkpoint" a scratch space. Used + * with `secp256k1_scratch_apply_checkpoint` to undo allocations. */ +static size_t secp256k1_scratch_checkpoint(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch); -/** Deallocates a stack frame */ -static void secp256k1_scratch_deallocate_frame(secp256k1_scratch* scratch); +/** Applies a check point received from `secp256k1_scratch_checkpoint`, + * undoing all allocations since that point. */ +static void secp256k1_scratch_apply_checkpoint(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t checkpoint); /** Returns the maximum allocation the scratch space will allow */ -static size_t secp256k1_scratch_max_allocation(const secp256k1_scratch* scratch, size_t n_objects); +static size_t secp256k1_scratch_max_allocation(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch, size_t n_objects); /** Returns a pointer into the most recently allocated frame, or NULL if there is insufficient available space */ -static void *secp256k1_scratch_alloc(secp256k1_scratch* scratch, size_t n); +static void *secp256k1_scratch_alloc(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t n); #endif diff --git a/src/secp256k1/src/scratch_impl.h b/src/secp256k1/src/scratch_impl.h index abed713b21d2..4cee70000147 100644 --- a/src/secp256k1/src/scratch_impl.h +++ b/src/secp256k1/src/scratch_impl.h @@ -7,78 +7,80 @@ #ifndef _SECP256K1_SCRATCH_IMPL_H_ #define _SECP256K1_SCRATCH_IMPL_H_ +#include "util.h" #include "scratch.h" -/* Using 16 bytes alignment because common architectures never have alignment - * requirements above 8 for any of the types we care about. In addition we - * leave some room because currently we don't care about a few bytes. - * TODO: Determine this at configure time. */ -#define ALIGNMENT 16 - -static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t max_size) { - secp256k1_scratch* ret = (secp256k1_scratch*)checked_malloc(error_callback, sizeof(*ret)); +static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t size) { + const size_t base_alloc = ((sizeof(secp256k1_scratch) + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT; + void *alloc = checked_malloc(error_callback, base_alloc + size); + secp256k1_scratch* ret = (secp256k1_scratch *)alloc; if (ret != NULL) { memset(ret, 0, sizeof(*ret)); - ret->max_size = max_size; - ret->error_callback = error_callback; + memcpy(ret->magic, "scratch", 8); + ret->data = (void *) ((char *) alloc + base_alloc); + ret->max_size = size; } return ret; } -static void secp256k1_scratch_destroy(secp256k1_scratch* scratch) { +static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch) { if (scratch != NULL) { - VERIFY_CHECK(scratch->frame == 0); + VERIFY_CHECK(scratch->alloc_size == 0); /* all checkpoints should be applied */ + if (memcmp(scratch->magic, "scratch", 8) != 0) { + secp256k1_callback_call(error_callback, "invalid scratch space"); + return; + } + memset(scratch->magic, 0, sizeof(scratch->magic)); free(scratch); } } -static size_t secp256k1_scratch_max_allocation(const secp256k1_scratch* scratch, size_t objects) { - size_t i = 0; - size_t allocated = 0; - for (i = 0; i < scratch->frame; i++) { - allocated += scratch->frame_size[i]; - } - if (scratch->max_size - allocated <= objects * ALIGNMENT) { +static size_t secp256k1_scratch_checkpoint(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch) { + if (memcmp(scratch->magic, "scratch", 8) != 0) { + secp256k1_callback_call(error_callback, "invalid scratch space"); return 0; } - return scratch->max_size - allocated - objects * ALIGNMENT; + return scratch->alloc_size; } -static int secp256k1_scratch_allocate_frame(secp256k1_scratch* scratch, size_t n, size_t objects) { - VERIFY_CHECK(scratch->frame < SECP256K1_SCRATCH_MAX_FRAMES); - - if (n <= secp256k1_scratch_max_allocation(scratch, objects)) { - n += objects * ALIGNMENT; - scratch->data[scratch->frame] = checked_malloc(scratch->error_callback, n); - if (scratch->data[scratch->frame] == NULL) { - return 0; - } - scratch->frame_size[scratch->frame] = n; - scratch->offset[scratch->frame] = 0; - scratch->frame++; - return 1; - } else { - return 0; +static void secp256k1_scratch_apply_checkpoint(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t checkpoint) { + if (memcmp(scratch->magic, "scratch", 8) != 0) { + secp256k1_callback_call(error_callback, "invalid scratch space"); + return; + } + if (checkpoint > scratch->alloc_size) { + secp256k1_callback_call(error_callback, "invalid checkpoint"); + return; } + scratch->alloc_size = checkpoint; } -static void secp256k1_scratch_deallocate_frame(secp256k1_scratch* scratch) { - VERIFY_CHECK(scratch->frame > 0); - scratch->frame -= 1; - free(scratch->data[scratch->frame]); +static size_t secp256k1_scratch_max_allocation(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch, size_t objects) { + if (memcmp(scratch->magic, "scratch", 8) != 0) { + secp256k1_callback_call(error_callback, "invalid scratch space"); + return 0; + } + if (scratch->max_size - scratch->alloc_size <= objects * (ALIGNMENT - 1)) { + return 0; + } + return scratch->max_size - scratch->alloc_size - objects * (ALIGNMENT - 1); } -static void *secp256k1_scratch_alloc(secp256k1_scratch* scratch, size_t size) { +static void *secp256k1_scratch_alloc(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t size) { void *ret; - size_t frame = scratch->frame - 1; - size = ((size + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT; + size = ROUND_TO_ALIGN(size); + + if (memcmp(scratch->magic, "scratch", 8) != 0) { + secp256k1_callback_call(error_callback, "invalid scratch space"); + return NULL; + } - if (scratch->frame == 0 || size + scratch->offset[frame] > scratch->frame_size[frame]) { + if (size > scratch->max_size - scratch->alloc_size) { return NULL; } - ret = (void *) ((unsigned char *) scratch->data[frame] + scratch->offset[frame]); + ret = (void *) ((char *) scratch->data + scratch->alloc_size); memset(ret, 0, size); - scratch->offset[frame] += size; + scratch->alloc_size += size; return ret; } diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c index 15981f46e21a..38c2b0d69edf 100644 --- a/src/secp256k1/src/secp256k1.c +++ b/src/secp256k1/src/secp256k1.c @@ -5,6 +5,7 @@ **********************************************************************/ #include "include/secp256k1.h" +#include "include/secp256k1_preallocated.h" #include "util.h" #include "num_impl.h" @@ -26,28 +27,39 @@ } \ } while(0) -static void default_illegal_callback_fn(const char* str, void* data) { +#define ARG_CHECK_NO_RETURN(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + secp256k1_callback_call(&ctx->illegal_callback, #cond); \ + } \ +} while(0) + +#ifndef USE_EXTERNAL_DEFAULT_CALLBACKS +#include +#include +static void secp256k1_default_illegal_callback_fn(const char* str, void* data) { (void)data; fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str); abort(); } - -static const secp256k1_callback default_illegal_callback = { - default_illegal_callback_fn, - NULL -}; - -static void default_error_callback_fn(const char* str, void* data) { +static void secp256k1_default_error_callback_fn(const char* str, void* data) { (void)data; fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); abort(); } +#else +void secp256k1_default_illegal_callback_fn(const char* str, void* data); +void secp256k1_default_error_callback_fn(const char* str, void* data); +#endif -static const secp256k1_callback default_error_callback = { - default_error_callback_fn, +static const secp256k1_callback default_illegal_callback = { + secp256k1_default_illegal_callback_fn, NULL }; +static const secp256k1_callback default_error_callback = { + secp256k1_default_error_callback_fn, + NULL +}; struct secp256k1_context_struct { secp256k1_ecmult_context ecmult_ctx; @@ -59,20 +71,55 @@ struct secp256k1_context_struct { static const secp256k1_context secp256k1_context_no_precomp_ = { { 0 }, { 0 }, - { default_illegal_callback_fn, 0 }, - { default_error_callback_fn, 0 } + { secp256k1_default_illegal_callback_fn, 0 }, + { secp256k1_default_error_callback_fn, 0 } }; const secp256k1_context *secp256k1_context_no_precomp = &secp256k1_context_no_precomp_; -secp256k1_context* secp256k1_context_create(unsigned int flags) { - secp256k1_context* ret = (secp256k1_context*)checked_malloc(&default_error_callback, sizeof(secp256k1_context)); +size_t secp256k1_context_preallocated_size(unsigned int flags) { + size_t ret = ROUND_TO_ALIGN(sizeof(secp256k1_context)); + + if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) { + secp256k1_callback_call(&default_illegal_callback, + "Invalid flags"); + return 0; + } + + if (flags & SECP256K1_FLAGS_BIT_CONTEXT_SIGN) { + ret += SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE; + } + if (flags & SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) { + ret += SECP256K1_ECMULT_CONTEXT_PREALLOCATED_SIZE; + } + return ret; +} + +size_t secp256k1_context_preallocated_clone_size(const secp256k1_context* ctx) { + size_t ret = ROUND_TO_ALIGN(sizeof(secp256k1_context)); + VERIFY_CHECK(ctx != NULL); + if (secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)) { + ret += SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE; + } + if (secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)) { + ret += SECP256K1_ECMULT_CONTEXT_PREALLOCATED_SIZE; + } + return ret; +} + +secp256k1_context* secp256k1_context_preallocated_create(void* prealloc, unsigned int flags) { + void* const base = prealloc; + size_t prealloc_size; + secp256k1_context* ret; + + VERIFY_CHECK(prealloc != NULL); + prealloc_size = secp256k1_context_preallocated_size(flags); + ret = (secp256k1_context*)manual_alloc(&prealloc, sizeof(secp256k1_context), base, prealloc_size); ret->illegal_callback = default_illegal_callback; ret->error_callback = default_error_callback; if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) { secp256k1_callback_call(&ret->illegal_callback, "Invalid flags"); - free(ret); return NULL; } @@ -80,47 +127,79 @@ secp256k1_context* secp256k1_context_create(unsigned int flags) { secp256k1_ecmult_gen_context_init(&ret->ecmult_gen_ctx); if (flags & SECP256K1_FLAGS_BIT_CONTEXT_SIGN) { - secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &ret->error_callback); + secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &prealloc); } if (flags & SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) { - secp256k1_ecmult_context_build(&ret->ecmult_ctx, &ret->error_callback); + secp256k1_ecmult_context_build(&ret->ecmult_ctx, &prealloc); + } + + return (secp256k1_context*) ret; +} + +secp256k1_context* secp256k1_context_create(unsigned int flags) { + size_t const prealloc_size = secp256k1_context_preallocated_size(flags); + secp256k1_context* ctx = (secp256k1_context*)checked_malloc(&default_error_callback, prealloc_size); + if (EXPECT(secp256k1_context_preallocated_create(ctx, flags) == NULL, 0)) { + free(ctx); + return NULL; } + return ctx; +} + +secp256k1_context* secp256k1_context_preallocated_clone(const secp256k1_context* ctx, void* prealloc) { + size_t prealloc_size; + secp256k1_context* ret; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(prealloc != NULL); + + prealloc_size = secp256k1_context_preallocated_clone_size(ctx); + ret = (secp256k1_context*)prealloc; + memcpy(ret, ctx, prealloc_size); + secp256k1_ecmult_gen_context_finalize_memcpy(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx); + secp256k1_ecmult_context_finalize_memcpy(&ret->ecmult_ctx, &ctx->ecmult_ctx); return ret; } secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) { - secp256k1_context* ret = (secp256k1_context*)checked_malloc(&ctx->error_callback, sizeof(secp256k1_context)); - ret->illegal_callback = ctx->illegal_callback; - ret->error_callback = ctx->error_callback; - secp256k1_ecmult_context_clone(&ret->ecmult_ctx, &ctx->ecmult_ctx, &ctx->error_callback); - secp256k1_ecmult_gen_context_clone(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx, &ctx->error_callback); + secp256k1_context* ret; + size_t prealloc_size; + + VERIFY_CHECK(ctx != NULL); + prealloc_size = secp256k1_context_preallocated_clone_size(ctx); + ret = (secp256k1_context*)checked_malloc(&ctx->error_callback, prealloc_size); + ret = secp256k1_context_preallocated_clone(ctx, ret); return ret; } -void secp256k1_context_destroy(secp256k1_context* ctx) { - CHECK(ctx != secp256k1_context_no_precomp); +void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) { + ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp); if (ctx != NULL) { secp256k1_ecmult_context_clear(&ctx->ecmult_ctx); secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); + } +} +void secp256k1_context_destroy(secp256k1_context* ctx) { + if (ctx != NULL) { + secp256k1_context_preallocated_destroy(ctx); free(ctx); } } void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { - CHECK(ctx != secp256k1_context_no_precomp); + ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp); if (fun == NULL) { - fun = default_illegal_callback_fn; + fun = secp256k1_default_illegal_callback_fn; } ctx->illegal_callback.fn = fun; ctx->illegal_callback.data = data; } void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { - CHECK(ctx != secp256k1_context_no_precomp); + ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp); if (fun == NULL) { - fun = default_error_callback_fn; + fun = secp256k1_default_error_callback_fn; } ctx->error_callback.fn = fun; ctx->error_callback.data = data; @@ -131,8 +210,9 @@ secp256k1_scratch_space* secp256k1_scratch_space_create(const secp256k1_context* return secp256k1_scratch_create(&ctx->error_callback, max_size); } -void secp256k1_scratch_space_destroy(secp256k1_scratch_space* scratch) { - secp256k1_scratch_destroy(scratch); +void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scratch_space* scratch) { + VERIFY_CHECK(ctx != NULL); + secp256k1_scratch_destroy(&ctx->error_callback, scratch); } static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) { @@ -333,6 +413,29 @@ static SECP256K1_INLINE void buffer_append(unsigned char *buf, unsigned int *off *offset += len; } +/* This nonce function is described in BIP-schnorr + * (https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki) */ +static int nonce_function_bipschnorr(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + secp256k1_sha256 sha; + (void) counter; + VERIFY_CHECK(counter == 0); + + /* Hash x||msg as per the spec */ + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, key32, 32); + secp256k1_sha256_write(&sha, msg32, 32); + /* Hash in algorithm, which is not in the spec, but may be critical to + * users depending on it to avoid nonce reuse across algorithms. */ + if (algo16 != NULL) { + secp256k1_sha256_write(&sha, algo16, 16); + } + if (data != NULL) { + secp256k1_sha256_write(&sha, data, 32); + } + secp256k1_sha256_finalize(&sha, nonce32); + return 1; +} + static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { unsigned char keydata[112]; unsigned int offset = 0; @@ -363,6 +466,7 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m return 1; } +const secp256k1_nonce_function secp256k1_nonce_function_bipschnorr = nonce_function_bipschnorr; const secp256k1_nonce_function secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979; const secp256k1_nonce_function secp256k1_nonce_function_default = nonce_function_rfc6979; @@ -438,7 +542,7 @@ int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *p ARG_CHECK(seckey != NULL); secp256k1_scalar_set_b32(&sec, seckey, &overflow); - ret = (!overflow) & (!secp256k1_scalar_is_zero(&sec)); + ret = !overflow && !secp256k1_scalar_is_zero(&sec); if (ret) { secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec); secp256k1_ge_set_gej(&p, &pj); @@ -457,6 +561,7 @@ int secp256k1_ec_privkey_negate(const secp256k1_context* ctx, unsigned char *sec secp256k1_scalar_negate(&sec, &sec); secp256k1_scalar_get_b32(seckey, &sec); + secp256k1_scalar_clear(&sec); return 1; } @@ -604,6 +709,10 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey * # include "modules/ecdh/main_impl.h" #endif +#ifdef ENABLE_MODULE_SCHNORRSIG +# include "modules/schnorrsig/main_impl.h" +#endif + #ifdef ENABLE_MODULE_RECOVERY # include "modules/recovery/main_impl.h" #endif diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c index f1c4db929a77..ed66e83ac84b 100644 --- a/src/secp256k1/src/tests.c +++ b/src/secp256k1/src/tests.c @@ -16,6 +16,7 @@ #include "secp256k1.c" #include "include/secp256k1.h" +#include "include/secp256k1_preallocated.h" #include "testrand_impl.h" #ifdef ENABLE_OPENSSL_TESTS @@ -82,7 +83,9 @@ void random_field_element_magnitude(secp256k1_fe *fe) { secp256k1_fe_negate(&zero, &zero, 0); secp256k1_fe_mul_int(&zero, n - 1); secp256k1_fe_add(fe, &zero); - VERIFY_CHECK(fe->magnitude == n); +#ifdef VERIFY + CHECK(fe->magnitude == n); +#endif } void random_group_element_test(secp256k1_ge *ge) { @@ -137,23 +140,47 @@ void random_scalar_order(secp256k1_scalar *num) { } while(1); } -void run_context_tests(void) { +void run_context_tests(int use_prealloc) { secp256k1_pubkey pubkey; secp256k1_pubkey zero_pubkey; secp256k1_ecdsa_signature sig; unsigned char ctmp[32]; int32_t ecount; int32_t ecount2; - secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); - secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); - secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + secp256k1_context *none; + secp256k1_context *sign; + secp256k1_context *vrfy; + secp256k1_context *both; + void *none_prealloc = NULL; + void *sign_prealloc = NULL; + void *vrfy_prealloc = NULL; + void *both_prealloc = NULL; secp256k1_gej pubj; secp256k1_ge pub; secp256k1_scalar msg, key, nonce; secp256k1_scalar sigr, sigs; + if (use_prealloc) { + none_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); + sign_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN)); + vrfy_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_VERIFY)); + both_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)); + CHECK(none_prealloc != NULL); + CHECK(sign_prealloc != NULL); + CHECK(vrfy_prealloc != NULL); + CHECK(both_prealloc != NULL); + none = secp256k1_context_preallocated_create(none_prealloc, SECP256K1_CONTEXT_NONE); + sign = secp256k1_context_preallocated_create(sign_prealloc, SECP256K1_CONTEXT_SIGN); + vrfy = secp256k1_context_preallocated_create(vrfy_prealloc, SECP256K1_CONTEXT_VERIFY); + both = secp256k1_context_preallocated_create(both_prealloc, SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + } else { + none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + } + memset(&zero_pubkey, 0, sizeof(zero_pubkey)); ecount = 0; @@ -163,14 +190,57 @@ void run_context_tests(void) { secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, NULL); CHECK(vrfy->error_callback.fn != sign->error_callback.fn); + /* check if sizes for cloning are consistent */ + CHECK(secp256k1_context_preallocated_clone_size(none) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); + CHECK(secp256k1_context_preallocated_clone_size(sign) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN)); + CHECK(secp256k1_context_preallocated_clone_size(vrfy) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_VERIFY)); + CHECK(secp256k1_context_preallocated_clone_size(both) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)); + /*** clone and destroy all of them to make sure cloning was complete ***/ { secp256k1_context *ctx_tmp; - ctx_tmp = none; none = secp256k1_context_clone(none); secp256k1_context_destroy(ctx_tmp); - ctx_tmp = sign; sign = secp256k1_context_clone(sign); secp256k1_context_destroy(ctx_tmp); - ctx_tmp = vrfy; vrfy = secp256k1_context_clone(vrfy); secp256k1_context_destroy(ctx_tmp); - ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_destroy(ctx_tmp); + if (use_prealloc) { + /* clone into a non-preallocated context and then again into a new preallocated one. */ + ctx_tmp = none; none = secp256k1_context_clone(none); secp256k1_context_preallocated_destroy(ctx_tmp); + free(none_prealloc); none_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(none_prealloc != NULL); + ctx_tmp = none; none = secp256k1_context_preallocated_clone(none, none_prealloc); secp256k1_context_destroy(ctx_tmp); + + ctx_tmp = sign; sign = secp256k1_context_clone(sign); secp256k1_context_preallocated_destroy(ctx_tmp); + free(sign_prealloc); sign_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN)); CHECK(sign_prealloc != NULL); + ctx_tmp = sign; sign = secp256k1_context_preallocated_clone(sign, sign_prealloc); secp256k1_context_destroy(ctx_tmp); + + ctx_tmp = vrfy; vrfy = secp256k1_context_clone(vrfy); secp256k1_context_preallocated_destroy(ctx_tmp); + free(vrfy_prealloc); vrfy_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_VERIFY)); CHECK(vrfy_prealloc != NULL); + ctx_tmp = vrfy; vrfy = secp256k1_context_preallocated_clone(vrfy, vrfy_prealloc); secp256k1_context_destroy(ctx_tmp); + + ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_preallocated_destroy(ctx_tmp); + free(both_prealloc); both_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)); CHECK(both_prealloc != NULL); + ctx_tmp = both; both = secp256k1_context_preallocated_clone(both, both_prealloc); secp256k1_context_destroy(ctx_tmp); + } else { + /* clone into a preallocated context and then again into a new non-preallocated one. */ + void *prealloc_tmp; + + prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(prealloc_tmp != NULL); + ctx_tmp = none; none = secp256k1_context_preallocated_clone(none, prealloc_tmp); secp256k1_context_destroy(ctx_tmp); + ctx_tmp = none; none = secp256k1_context_clone(none); secp256k1_context_preallocated_destroy(ctx_tmp); + free(prealloc_tmp); + + prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN)); CHECK(prealloc_tmp != NULL); + ctx_tmp = sign; sign = secp256k1_context_preallocated_clone(sign, prealloc_tmp); secp256k1_context_destroy(ctx_tmp); + ctx_tmp = sign; sign = secp256k1_context_clone(sign); secp256k1_context_preallocated_destroy(ctx_tmp); + free(prealloc_tmp); + + prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_VERIFY)); CHECK(prealloc_tmp != NULL); + ctx_tmp = vrfy; vrfy = secp256k1_context_preallocated_clone(vrfy, prealloc_tmp); secp256k1_context_destroy(ctx_tmp); + ctx_tmp = vrfy; vrfy = secp256k1_context_clone(vrfy); secp256k1_context_preallocated_destroy(ctx_tmp); + free(prealloc_tmp); + + prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)); CHECK(prealloc_tmp != NULL); + ctx_tmp = both; both = secp256k1_context_preallocated_clone(both, prealloc_tmp); secp256k1_context_destroy(ctx_tmp); + ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_preallocated_destroy(ctx_tmp); + free(prealloc_tmp); + } } /* Verify that the error callback makes it across the clone. */ @@ -229,10 +299,6 @@ void run_context_tests(void) { secp256k1_context_set_illegal_callback(vrfy, NULL, NULL); secp256k1_context_set_illegal_callback(sign, NULL, NULL); - /* This shouldn't leak memory, due to already-set tests. */ - secp256k1_ecmult_gen_context_build(&sign->ecmult_gen_ctx, NULL); - secp256k1_ecmult_context_build(&vrfy->ecmult_ctx, NULL); - /* obtain a working nonce */ do { random_scalar_order_test(&nonce); @@ -247,49 +313,95 @@ void run_context_tests(void) { CHECK(secp256k1_ecdsa_sig_verify(&both->ecmult_ctx, &sigr, &sigs, &pub, &msg)); /* cleanup */ - secp256k1_context_destroy(none); - secp256k1_context_destroy(sign); - secp256k1_context_destroy(vrfy); - secp256k1_context_destroy(both); + if (use_prealloc) { + secp256k1_context_preallocated_destroy(none); + secp256k1_context_preallocated_destroy(sign); + secp256k1_context_preallocated_destroy(vrfy); + secp256k1_context_preallocated_destroy(both); + free(none_prealloc); + free(sign_prealloc); + free(vrfy_prealloc); + free(both_prealloc); + } else { + secp256k1_context_destroy(none); + secp256k1_context_destroy(sign); + secp256k1_context_destroy(vrfy); + secp256k1_context_destroy(both); + } /* Defined as no-op. */ secp256k1_context_destroy(NULL); + secp256k1_context_preallocated_destroy(NULL); + } void run_scratch_tests(void) { + const size_t adj_alloc = ((500 + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT; + int32_t ecount = 0; + size_t checkpoint; + size_t checkpoint_2; secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); secp256k1_scratch_space *scratch; + secp256k1_scratch_space local_scratch; /* Test public API */ secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); scratch = secp256k1_scratch_space_create(none, 1000); CHECK(scratch != NULL); CHECK(ecount == 0); /* Test internal API */ - CHECK(secp256k1_scratch_max_allocation(scratch, 0) == 1000); - CHECK(secp256k1_scratch_max_allocation(scratch, 1) < 1000); - - /* Allocating 500 bytes with no frame fails */ - CHECK(secp256k1_scratch_alloc(scratch, 500) == NULL); - CHECK(secp256k1_scratch_max_allocation(scratch, 0) == 1000); - - /* ...but pushing a new stack frame does affect the max allocation */ - CHECK(secp256k1_scratch_allocate_frame(scratch, 500, 1 == 1)); - CHECK(secp256k1_scratch_max_allocation(scratch, 1) < 500); /* 500 - ALIGNMENT */ - CHECK(secp256k1_scratch_alloc(scratch, 500) != NULL); - CHECK(secp256k1_scratch_alloc(scratch, 500) == NULL); - - CHECK(secp256k1_scratch_allocate_frame(scratch, 500, 1) == 0); + CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000); + CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 1) == 1000 - (ALIGNMENT - 1)); + CHECK(scratch->alloc_size == 0); + CHECK(scratch->alloc_size % ALIGNMENT == 0); + + /* Allocating 500 bytes succeeds */ + checkpoint = secp256k1_scratch_checkpoint(&none->error_callback, scratch); + CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) != NULL); + CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000 - adj_alloc); + CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1)); + CHECK(scratch->alloc_size != 0); + CHECK(scratch->alloc_size % ALIGNMENT == 0); + + /* Allocating another 500 bytes fails */ + CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) == NULL); + CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000 - adj_alloc); + CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1)); + CHECK(scratch->alloc_size != 0); + CHECK(scratch->alloc_size % ALIGNMENT == 0); + + /* ...but it succeeds once we apply the checkpoint to undo it */ + secp256k1_scratch_apply_checkpoint(&none->error_callback, scratch, checkpoint); + CHECK(scratch->alloc_size == 0); + CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000); + CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) != NULL); + CHECK(scratch->alloc_size != 0); + + /* try to apply a bad checkpoint */ + checkpoint_2 = secp256k1_scratch_checkpoint(&none->error_callback, scratch); + secp256k1_scratch_apply_checkpoint(&none->error_callback, scratch, checkpoint); + CHECK(ecount == 0); + secp256k1_scratch_apply_checkpoint(&none->error_callback, scratch, checkpoint_2); /* checkpoint_2 is after checkpoint */ + CHECK(ecount == 1); + secp256k1_scratch_apply_checkpoint(&none->error_callback, scratch, (size_t) -1); /* this is just wildly invalid */ + CHECK(ecount == 2); - /* ...and this effect is undone by popping the frame */ - secp256k1_scratch_deallocate_frame(scratch); - CHECK(secp256k1_scratch_max_allocation(scratch, 0) == 1000); - CHECK(secp256k1_scratch_alloc(scratch, 500) == NULL); + /* try to use badly initialized scratch space */ + secp256k1_scratch_space_destroy(none, scratch); + memset(&local_scratch, 0, sizeof(local_scratch)); + scratch = &local_scratch; + CHECK(!secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0)); + CHECK(ecount == 3); + CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) == NULL); + CHECK(ecount == 4); + secp256k1_scratch_space_destroy(none, scratch); + CHECK(ecount == 5); /* cleanup */ - secp256k1_scratch_space_destroy(scratch); + secp256k1_scratch_space_destroy(none, NULL); /* no-op */ secp256k1_context_destroy(none); } @@ -965,12 +1077,122 @@ void scalar_test(void) { } +void scalar_chacha_tests(void) { + /* Test vectors 1 to 4 from https://tools.ietf.org/html/rfc8439#appendix-A + * Note that scalar_set_b32 and scalar_get_b32 represent integers + * underlying the scalar in big-endian format. */ + unsigned char expected1[64] = { + 0xad, 0xe0, 0xb8, 0x76, 0x90, 0x3d, 0xf1, 0xa0, + 0xe5, 0x6a, 0x5d, 0x40, 0x28, 0xbd, 0x86, 0x53, + 0xb8, 0x19, 0xd2, 0xbd, 0x1a, 0xed, 0x8d, 0xa0, + 0xcc, 0xef, 0x36, 0xa8, 0xc7, 0x0d, 0x77, 0x8b, + 0x7c, 0x59, 0x41, 0xda, 0x8d, 0x48, 0x57, 0x51, + 0x3f, 0xe0, 0x24, 0x77, 0x37, 0x4a, 0xd8, 0xb8, + 0xf4, 0xb8, 0x43, 0x6a, 0x1c, 0xa1, 0x18, 0x15, + 0x69, 0xb6, 0x87, 0xc3, 0x86, 0x65, 0xee, 0xb2 + }; + unsigned char expected2[64] = { + 0xbe, 0xe7, 0x07, 0x9f, 0x7a, 0x38, 0x51, 0x55, + 0x7c, 0x97, 0xba, 0x98, 0x0d, 0x08, 0x2d, 0x73, + 0xa0, 0x29, 0x0f, 0xcb, 0x69, 0x65, 0xe3, 0x48, + 0x3e, 0x53, 0xc6, 0x12, 0xed, 0x7a, 0xee, 0x32, + 0x76, 0x21, 0xb7, 0x29, 0x43, 0x4e, 0xe6, 0x9c, + 0xb0, 0x33, 0x71, 0xd5, 0xd5, 0x39, 0xd8, 0x74, + 0x28, 0x1f, 0xed, 0x31, 0x45, 0xfb, 0x0a, 0x51, + 0x1f, 0x0a, 0xe1, 0xac, 0x6f, 0x4d, 0x79, 0x4b + }; + unsigned char seed3[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + }; + unsigned char expected3[64] = { + 0x24, 0x52, 0xeb, 0x3a, 0x92, 0x49, 0xf8, 0xec, + 0x8d, 0x82, 0x9d, 0x9b, 0xdd, 0xd4, 0xce, 0xb1, + 0xe8, 0x25, 0x20, 0x83, 0x60, 0x81, 0x8b, 0x01, + 0xf3, 0x84, 0x22, 0xb8, 0x5a, 0xaa, 0x49, 0xc9, + 0xbb, 0x00, 0xca, 0x8e, 0xda, 0x3b, 0xa7, 0xb4, + 0xc4, 0xb5, 0x92, 0xd1, 0xfd, 0xf2, 0x73, 0x2f, + 0x44, 0x36, 0x27, 0x4e, 0x25, 0x61, 0xb3, 0xc8, + 0xeb, 0xdd, 0x4a, 0xa6, 0xa0, 0x13, 0x6c, 0x00 + }; + unsigned char seed4[32] = { + 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + unsigned char expected4[64] = { + 0xfb, 0x4d, 0xd5, 0x72, 0x4b, 0xc4, 0x2e, 0xf1, + 0xdf, 0x92, 0x26, 0x36, 0x32, 0x7f, 0x13, 0x94, + 0xa7, 0x8d, 0xea, 0x8f, 0x5e, 0x26, 0x90, 0x39, + 0xa1, 0xbe, 0xbb, 0xc1, 0xca, 0xf0, 0x9a, 0xae, + 0xa2, 0x5a, 0xb2, 0x13, 0x48, 0xa6, 0xb4, 0x6c, + 0x1b, 0x9d, 0x9b, 0xcb, 0x09, 0x2c, 0x5b, 0xe6, + 0x54, 0x6c, 0xa6, 0x24, 0x1b, 0xec, 0x45, 0xd5, + 0x87, 0xf4, 0x74, 0x73, 0x96, 0xf0, 0x99, 0x2e + }; + unsigned char seed5[32] = { + 0x32, 0x56, 0x56, 0xf4, 0x29, 0x02, 0xc2, 0xf8, + 0xa3, 0x4b, 0x96, 0xf5, 0xa7, 0xf7, 0xe3, 0x6c, + 0x92, 0xad, 0xa5, 0x18, 0x1c, 0xe3, 0x41, 0xae, + 0xc3, 0xf3, 0x18, 0xd0, 0xfa, 0x5b, 0x72, 0x53 + }; + unsigned char expected5[64] = { + 0xe7, 0x56, 0xd3, 0x28, 0xe9, 0xc6, 0x19, 0x5c, + 0x6f, 0x17, 0x8e, 0x21, 0x8c, 0x1e, 0x72, 0x11, + 0xe7, 0xbd, 0x17, 0x0d, 0xac, 0x14, 0xad, 0xe9, + 0x3d, 0x9f, 0xb6, 0x92, 0xd6, 0x09, 0x20, 0xfb, + 0x43, 0x8e, 0x3b, 0x6d, 0xe3, 0x33, 0xdc, 0xc7, + 0x6c, 0x07, 0x6f, 0xbb, 0x1f, 0xb4, 0xc8, 0xb5, + 0xe3, 0x6c, 0xe5, 0x12, 0xd9, 0xd7, 0x64, 0x0c, + 0xf5, 0xa7, 0x0d, 0xab, 0x79, 0x03, 0xf1, 0x81 + }; + + secp256k1_scalar exp_r1, exp_r2; + secp256k1_scalar r1, r2; + unsigned char seed0[32] = { 0 }; + + secp256k1_scalar_chacha20(&r1, &r2, seed0, 0); + secp256k1_scalar_set_b32(&exp_r1, &expected1[0], NULL); + secp256k1_scalar_set_b32(&exp_r2, &expected1[32], NULL); + CHECK(secp256k1_scalar_eq(&exp_r1, &r1)); + CHECK(secp256k1_scalar_eq(&exp_r2, &r2)); + + secp256k1_scalar_chacha20(&r1, &r2, seed0, 1); + secp256k1_scalar_set_b32(&exp_r1, &expected2[0], NULL); + secp256k1_scalar_set_b32(&exp_r2, &expected2[32], NULL); + CHECK(secp256k1_scalar_eq(&exp_r1, &r1)); + CHECK(secp256k1_scalar_eq(&exp_r2, &r2)); + + secp256k1_scalar_chacha20(&r1, &r2, seed3, 1); + secp256k1_scalar_set_b32(&exp_r1, &expected3[0], NULL); + secp256k1_scalar_set_b32(&exp_r2, &expected3[32], NULL); + CHECK(secp256k1_scalar_eq(&exp_r1, &r1)); + CHECK(secp256k1_scalar_eq(&exp_r2, &r2)); + + secp256k1_scalar_chacha20(&r1, &r2, seed4, 2); + secp256k1_scalar_set_b32(&exp_r1, &expected4[0], NULL); + secp256k1_scalar_set_b32(&exp_r2, &expected4[32], NULL); + CHECK(secp256k1_scalar_eq(&exp_r1, &r1)); + CHECK(secp256k1_scalar_eq(&exp_r2, &r2)); + + secp256k1_scalar_chacha20(&r1, &r2, seed5, 0x6ff8602a7a78e2f2ULL); + secp256k1_scalar_set_b32(&exp_r1, &expected5[0], NULL); + secp256k1_scalar_set_b32(&exp_r2, &expected5[32], NULL); + CHECK(secp256k1_scalar_eq(&exp_r1, &r1)); + CHECK(secp256k1_scalar_eq(&exp_r2, &r2)); +} + void run_scalar_tests(void) { int i; for (i = 0; i < 128 * count; i++) { scalar_test(); } + scalar_chacha_tests(); + { /* (-1)+1 should be zero. */ secp256k1_scalar s, o; @@ -1709,24 +1931,32 @@ void run_field_misc(void) { /* Test fe conditional move; z is not normalized here. */ q = x; secp256k1_fe_cmov(&x, &z, 0); - VERIFY_CHECK(!x.normalized && x.magnitude == z.magnitude); +#ifdef VERIFY + CHECK(!x.normalized && x.magnitude == z.magnitude); +#endif secp256k1_fe_cmov(&x, &x, 1); CHECK(fe_memcmp(&x, &z) != 0); CHECK(fe_memcmp(&x, &q) == 0); secp256k1_fe_cmov(&q, &z, 1); - VERIFY_CHECK(!q.normalized && q.magnitude == z.magnitude); +#ifdef VERIFY + CHECK(!q.normalized && q.magnitude == z.magnitude); +#endif CHECK(fe_memcmp(&q, &z) == 0); secp256k1_fe_normalize_var(&x); secp256k1_fe_normalize_var(&z); CHECK(!secp256k1_fe_equal_var(&x, &z)); secp256k1_fe_normalize_var(&q); secp256k1_fe_cmov(&q, &z, (i&1)); - VERIFY_CHECK(q.normalized && q.magnitude == 1); +#ifdef VERIFY + CHECK(q.normalized && q.magnitude == 1); +#endif for (j = 0; j < 6; j++) { secp256k1_fe_negate(&z, &z, j+1); secp256k1_fe_normalize_var(&q); secp256k1_fe_cmov(&q, &z, (j&1)); - VERIFY_CHECK(!q.normalized && q.magnitude == (j+2)); +#ifdef VERIFY + CHECK(!q.normalized && q.magnitude == (j+2)); +#endif } secp256k1_fe_normalize_var(&z); /* Test storage conversion and conditional moves. */ @@ -2572,14 +2802,13 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e secp256k1_gej r; secp256k1_gej r2; ecmult_multi_data data; - secp256k1_scratch *scratch_empty; data.sc = sc; data.pt = pt; secp256k1_scalar_set_int(&szero, 0); /* No points to multiply */ - CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, NULL, ecmult_multi_callback, &data, 0)); + CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, NULL, ecmult_multi_callback, &data, 0)); /* Check 1- and 2-point multiplies against ecmult */ for (ncount = 0; ncount < count; ncount++) { @@ -2595,36 +2824,31 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e /* only G scalar */ secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &szero, &sc[0]); - CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &sc[0], ecmult_multi_callback, &data, 0)); + CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &sc[0], ecmult_multi_callback, &data, 0)); secp256k1_gej_neg(&r2, &r2); secp256k1_gej_add_var(&r, &r, &r2, NULL); CHECK(secp256k1_gej_is_infinity(&r)); /* 1-point */ secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &sc[0], &szero); - CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 1)); + CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 1)); secp256k1_gej_neg(&r2, &r2); secp256k1_gej_add_var(&r, &r, &r2, NULL); CHECK(secp256k1_gej_is_infinity(&r)); - /* Try to multiply 1 point, but scratch space is empty */ - scratch_empty = secp256k1_scratch_create(&ctx->error_callback, 0); - CHECK(!ecmult_multi(&ctx->ecmult_ctx, scratch_empty, &r, &szero, ecmult_multi_callback, &data, 1)); - secp256k1_scratch_destroy(scratch_empty); - /* Try to multiply 1 point, but callback returns false */ - CHECK(!ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_false_callback, &data, 1)); + CHECK(!ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_false_callback, &data, 1)); /* 2-point */ secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &sc[0], &sc[1]); - CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 2)); + CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 2)); secp256k1_gej_neg(&r2, &r2); secp256k1_gej_add_var(&r, &r, &r2, NULL); CHECK(secp256k1_gej_is_infinity(&r)); /* 2-point with G scalar */ secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &sc[0], &sc[1]); - CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &sc[1], ecmult_multi_callback, &data, 1)); + CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &sc[1], ecmult_multi_callback, &data, 1)); secp256k1_gej_neg(&r2, &r2); secp256k1_gej_add_var(&r, &r, &r2, NULL); CHECK(secp256k1_gej_is_infinity(&r)); @@ -2641,7 +2865,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e random_scalar_order(&sc[i]); secp256k1_ge_set_infinity(&pt[i]); } - CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j])); + CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j])); CHECK(secp256k1_gej_is_infinity(&r)); } @@ -2651,7 +2875,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e pt[i] = ptg; secp256k1_scalar_set_int(&sc[i], 0); } - CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j])); + CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j])); CHECK(secp256k1_gej_is_infinity(&r)); } @@ -2664,7 +2888,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e pt[2 * i + 1] = ptg; } - CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j])); + CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j])); CHECK(secp256k1_gej_is_infinity(&r)); random_scalar_order(&sc[0]); @@ -2677,7 +2901,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e secp256k1_ge_neg(&pt[2*i+1], &pt[2*i]); } - CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j])); + CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j])); CHECK(secp256k1_gej_is_infinity(&r)); } @@ -2692,7 +2916,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e secp256k1_scalar_negate(&sc[i], &sc[i]); } - CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 32)); + CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 32)); CHECK(secp256k1_gej_is_infinity(&r)); } @@ -2711,7 +2935,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e } secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &r, &sc[0], &szero); - CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20)); + CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20)); secp256k1_gej_neg(&r2, &r2); secp256k1_gej_add_var(&r, &r, &r2, NULL); CHECK(secp256k1_gej_is_infinity(&r)); @@ -2734,7 +2958,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e secp256k1_gej_set_ge(&p0j, &pt[0]); secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &p0j, &rs, &szero); - CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20)); + CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20)); secp256k1_gej_neg(&r2, &r2); secp256k1_gej_add_var(&r, &r, &r2, NULL); CHECK(secp256k1_gej_is_infinity(&r)); @@ -2747,13 +2971,13 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e } secp256k1_scalar_clear(&sc[0]); - CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20)); + CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20)); secp256k1_scalar_clear(&sc[1]); secp256k1_scalar_clear(&sc[2]); secp256k1_scalar_clear(&sc[3]); secp256k1_scalar_clear(&sc[4]); - CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 6)); - CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 5)); + CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 6)); + CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 5)); CHECK(secp256k1_gej_is_infinity(&r)); /* Run through s0*(t0*P) + s1*(t1*P) exhaustively for many small values of s0, s1, t0, t1 */ @@ -2798,7 +3022,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e secp256k1_scalar_add(&tmp1, &tmp1, &tmp2); secp256k1_ecmult(&ctx->ecmult_ctx, &expected, &ptgj, &tmp1, &szero); - CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &actual, &szero, ecmult_multi_callback, &data, 2)); + CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &actual, &szero, ecmult_multi_callback, &data, 2)); secp256k1_gej_neg(&expected, &expected); secp256k1_gej_add_var(&actual, &actual, &expected, NULL); CHECK(secp256k1_gej_is_infinity(&actual)); @@ -2809,6 +3033,24 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e } } +void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_multi) { + secp256k1_scalar szero; + secp256k1_scalar sc[32]; + secp256k1_ge pt[32]; + secp256k1_gej r; + ecmult_multi_data data; + secp256k1_scratch *scratch_empty; + + data.sc = sc; + data.pt = pt; + secp256k1_scalar_set_int(&szero, 0); + + /* Try to multiply 1 point, but scratch space is empty.*/ + scratch_empty = secp256k1_scratch_create(&ctx->error_callback, 0); + CHECK(!ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch_empty, &r, &szero, ecmult_multi_callback, &data, 1)); + secp256k1_scratch_destroy(&ctx->error_callback, scratch_empty); +} + void test_secp256k1_pippenger_bucket_window_inv(void) { int i; @@ -2839,17 +3081,27 @@ void test_ecmult_multi_pippenger_max_points(void) { int bucket_window = 0; for(; scratch_size < max_size; scratch_size+=256) { + size_t i; + size_t total_alloc; + size_t checkpoint; scratch = secp256k1_scratch_create(&ctx->error_callback, scratch_size); CHECK(scratch != NULL); - n_points_supported = secp256k1_pippenger_max_points(scratch); + checkpoint = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch); + n_points_supported = secp256k1_pippenger_max_points(&ctx->error_callback, scratch); if (n_points_supported == 0) { - secp256k1_scratch_destroy(scratch); + secp256k1_scratch_destroy(&ctx->error_callback, scratch); continue; } bucket_window = secp256k1_pippenger_bucket_window(n_points_supported); - CHECK(secp256k1_scratch_allocate_frame(scratch, secp256k1_pippenger_scratch_size(n_points_supported, bucket_window), PIPPENGER_SCRATCH_OBJECTS)); - secp256k1_scratch_deallocate_frame(scratch); - secp256k1_scratch_destroy(scratch); + /* allocate `total_alloc` bytes over `PIPPENGER_SCRATCH_OBJECTS` many allocations */ + total_alloc = secp256k1_pippenger_scratch_size(n_points_supported, bucket_window); + for (i = 0; i < PIPPENGER_SCRATCH_OBJECTS - 1; i++) { + CHECK(secp256k1_scratch_alloc(&ctx->error_callback, scratch, 1)); + total_alloc--; + } + CHECK(secp256k1_scratch_alloc(&ctx->error_callback, scratch, total_alloc)); + secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, checkpoint); + secp256k1_scratch_destroy(&ctx->error_callback, scratch); } CHECK(bucket_window == PIPPENGER_MAX_BUCKET_WINDOW); } @@ -2932,19 +3184,25 @@ void test_ecmult_multi_batching(void) { } data.sc = sc; data.pt = pt; + secp256k1_gej_neg(&r2, &r2); - /* Test with empty scratch space */ + /* Test with empty scratch space. It should compute the correct result using + * ecmult_mult_simple algorithm which doesn't require a scratch space. */ scratch = secp256k1_scratch_create(&ctx->error_callback, 0); - CHECK(!secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, 1)); - secp256k1_scratch_destroy(scratch); + CHECK(secp256k1_ecmult_multi_var(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, n_points)); + secp256k1_gej_add_var(&r, &r, &r2, NULL); + CHECK(secp256k1_gej_is_infinity(&r)); + secp256k1_scratch_destroy(&ctx->error_callback, scratch); /* Test with space for 1 point in pippenger. That's not enough because - * ecmult_multi selects strauss which requires more memory. */ + * ecmult_multi selects strauss which requires more memory. It should + * therefore select the simple algorithm. */ scratch = secp256k1_scratch_create(&ctx->error_callback, secp256k1_pippenger_scratch_size(1, 1) + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT); - CHECK(!secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, 1)); - secp256k1_scratch_destroy(scratch); + CHECK(secp256k1_ecmult_multi_var(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, n_points)); + secp256k1_gej_add_var(&r, &r, &r2, NULL); + CHECK(secp256k1_gej_is_infinity(&r)); + secp256k1_scratch_destroy(&ctx->error_callback, scratch); - secp256k1_gej_neg(&r2, &r2); for(i = 1; i <= n_points; i++) { if (i > ECMULT_PIPPENGER_THRESHOLD) { int bucket_window = secp256k1_pippenger_bucket_window(i); @@ -2954,10 +3212,10 @@ void test_ecmult_multi_batching(void) { size_t scratch_size = secp256k1_strauss_scratch_size(i); scratch = secp256k1_scratch_create(&ctx->error_callback, scratch_size + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT); } - CHECK(secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, n_points)); + CHECK(secp256k1_ecmult_multi_var(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, n_points)); secp256k1_gej_add_var(&r, &r, &r2, NULL); CHECK(secp256k1_gej_is_infinity(&r)); - secp256k1_scratch_destroy(scratch); + secp256k1_scratch_destroy(&ctx->error_callback, scratch); } free(sc); free(pt); @@ -2972,13 +3230,15 @@ void run_ecmult_multi_tests(void) { test_ecmult_multi(scratch, secp256k1_ecmult_multi_var); test_ecmult_multi(NULL, secp256k1_ecmult_multi_var); test_ecmult_multi(scratch, secp256k1_ecmult_pippenger_batch_single); + test_ecmult_multi_batch_single(secp256k1_ecmult_pippenger_batch_single); test_ecmult_multi(scratch, secp256k1_ecmult_strauss_batch_single); - secp256k1_scratch_destroy(scratch); + test_ecmult_multi_batch_single(secp256k1_ecmult_strauss_batch_single); + secp256k1_scratch_destroy(&ctx->error_callback, scratch); /* Run test_ecmult_multi with space for exactly one point */ scratch = secp256k1_scratch_create(&ctx->error_callback, secp256k1_strauss_scratch_size(1) + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT); test_ecmult_multi(scratch, secp256k1_ecmult_multi_var); - secp256k1_scratch_destroy(scratch); + secp256k1_scratch_destroy(&ctx->error_callback, scratch); test_ecmult_multi_batch_size_helper(); test_ecmult_multi_batching(); @@ -3050,7 +3310,7 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) { } bits = 128; #endif - skew = secp256k1_wnaf_const(wnaf, num, w, bits); + skew = secp256k1_wnaf_const(wnaf, &num, w, bits); for (i = WNAF_SIZE_BITS(bits, w); i >= 0; --i) { secp256k1_scalar t; @@ -4315,7 +4575,7 @@ int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_ if (valid_der) { ret |= (!roundtrips_der_lax) << 12; ret |= (len_der != len_der_lax) << 13; - ret |= (memcmp(roundtrip_der_lax, roundtrip_der, len_der) != 0) << 14; + ret |= ((len_der != len_der_lax) || (memcmp(roundtrip_der_lax, roundtrip_der, len_der) != 0)) << 14; } ret |= (roundtrips_der != roundtrips_der_lax) << 15; if (parsed_der) { @@ -4356,7 +4616,7 @@ int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_ ret |= (roundtrips_der != roundtrips_openssl) << 7; if (roundtrips_openssl) { ret |= (len_der != (size_t)len_openssl) << 8; - ret |= (memcmp(roundtrip_der, roundtrip_openssl, len_der) != 0) << 9; + ret |= ((len_der != (size_t)len_openssl) || (memcmp(roundtrip_der, roundtrip_openssl, len_der) != 0)) << 9; } #endif return ret; @@ -5012,6 +5272,10 @@ void run_ecdsa_openssl(void) { # include "modules/ecdh/tests_impl.h" #endif +#ifdef ENABLE_MODULE_SCHNORRSIG +# include "modules/schnorrsig/tests_impl.h" +#endif + #ifdef ENABLE_MODULE_RECOVERY # include "modules/recovery/tests_impl.h" #endif @@ -5062,7 +5326,8 @@ int main(int argc, char **argv) { printf("random seed = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", seed16[0], seed16[1], seed16[2], seed16[3], seed16[4], seed16[5], seed16[6], seed16[7], seed16[8], seed16[9], seed16[10], seed16[11], seed16[12], seed16[13], seed16[14], seed16[15]); /* initialize */ - run_context_tests(); + run_context_tests(0); + run_context_tests(1); run_scratch_tests(); ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); if (secp256k1_rand_bits(1)) { @@ -5124,6 +5389,11 @@ int main(int argc, char **argv) { run_ecdh_tests(); #endif +#ifdef ENABLE_MODULE_SCHNORRSIG + /* Schnorrsig tests */ + run_schnorrsig_tests(); +#endif + /* ecdsa tests */ run_random_pubkeys(); run_ecdsa_der_parse(); diff --git a/src/secp256k1/src/tests_exhaustive.c b/src/secp256k1/src/tests_exhaustive.c index ab9779b02fc5..b44e357cb69c 100644 --- a/src/secp256k1/src/tests_exhaustive.c +++ b/src/secp256k1/src/tests_exhaustive.c @@ -212,14 +212,14 @@ void test_exhaustive_ecmult_multi(const secp256k1_context *ctx, const secp256k1_ data.pt[0] = group[x]; data.pt[1] = group[y]; - secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &tmp, &g_sc, ecmult_multi_callback, &data, 2); + secp256k1_ecmult_multi_var(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &tmp, &g_sc, ecmult_multi_callback, &data, 2); ge_equals_gej(&group[(i * x + j * y + k) % order], &tmp); } } } } } - secp256k1_scratch_destroy(scratch); + secp256k1_scratch_destroy(&ctx->error_callback, scratch); } void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k) { diff --git a/src/secp256k1/src/util.h b/src/secp256k1/src/util.h index e1f5b764527d..9deb61bc59d1 100644 --- a/src/secp256k1/src/util.h +++ b/src/secp256k1/src/util.h @@ -84,6 +84,47 @@ static SECP256K1_INLINE void *checked_realloc(const secp256k1_callback* cb, void return ret; } +#if defined(__BIGGEST_ALIGNMENT__) +#define ALIGNMENT __BIGGEST_ALIGNMENT__ +#else +/* Using 16 bytes alignment because common architectures never have alignment + * requirements above 8 for any of the types we care about. In addition we + * leave some room because currently we don't care about a few bytes. */ +#define ALIGNMENT 16 +#endif + +#define ROUND_TO_ALIGN(size) (((size + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT) + +/* Assume there is a contiguous memory object with bounds [base, base + max_size) + * of which the memory range [base, *prealloc_ptr) is already allocated for usage, + * where *prealloc_ptr is an aligned pointer. In that setting, this functions + * reserves the subobject [*prealloc_ptr, *prealloc_ptr + alloc_size) of + * alloc_size bytes by increasing *prealloc_ptr accordingly, taking into account + * alignment requirements. + * + * The function returns an aligned pointer to the newly allocated subobject. + * + * This is useful for manual memory management: if we're simply given a block + * [base, base + max_size), the caller can use this function to allocate memory + * in this block and keep track of the current allocation state with *prealloc_ptr. + * + * It is VERIFY_CHECKed that there is enough space left in the memory object and + * *prealloc_ptr is aligned relative to base. + */ +static SECP256K1_INLINE void *manual_alloc(void** prealloc_ptr, size_t alloc_size, void* base, size_t max_size) { + size_t aligned_alloc_size = ROUND_TO_ALIGN(alloc_size); + void* ret; + VERIFY_CHECK(prealloc_ptr != NULL); + VERIFY_CHECK(*prealloc_ptr != NULL); + VERIFY_CHECK(base != NULL); + VERIFY_CHECK((unsigned char*)*prealloc_ptr >= (unsigned char*)base); + VERIFY_CHECK(((unsigned char*)*prealloc_ptr - (unsigned char*)base) % ALIGNMENT == 0); + VERIFY_CHECK((unsigned char*)*prealloc_ptr - (unsigned char*)base + aligned_alloc_size <= max_size); + ret = *prealloc_ptr; + *((unsigned char**)prealloc_ptr) += aligned_alloc_size; + return ret; +} + /* Macro for restrict, when available and not in a VERIFY build. */ #if defined(SECP256K1_BUILD) && defined(VERIFY) # define SECP256K1_RESTRICT diff --git a/src/validation.cpp b/src/validation.cpp index 74f68a30471d..b105d3809bca 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -774,7 +774,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. - PrecomputedTransactionData txdata(tx); + PrecomputedTransactionData txdata; if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true, false, txdata)) { // SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we // need to turn both off, and compare against just turning off CLEANSTACK @@ -1330,11 +1330,17 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi return true; } + std::vector spent_outputs; + spent_outputs.reserve(tx.vin.size()); for (unsigned int i = 0; i < tx.vin.size(); i++) { const COutPoint &prevout = tx.vin[i].prevout; const Coin& coin = inputs.AccessCoin(prevout); assert(!coin.IsSpent()); + spent_outputs.emplace_back(coin.out); + } + txdata.Init(tx, std::move(spent_outputs)); + for (unsigned int i = 0; i < tx.vin.size(); i++) { // We very carefully only pass in things to CScriptCheck which // are clearly committed to by tx' witness hash. This provides // a sanity check that our caching is not introducing consensus @@ -1342,7 +1348,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi // spent being checked as a part of CScriptCheck. // Verify signature - CScriptCheck check(coin.out, tx, i, flags, cacheSigStore, &txdata); + CScriptCheck check(txdata.m_spent_outputs[i], tx, i, flags, cacheSigStore, &txdata); if (pvChecks) { pvChecks->push_back(CScriptCheck()); check.swap(pvChecks->back()); @@ -1356,7 +1362,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi // splitting the network between upgraded and // non-upgraded nodes by banning CONSENSUS-failing // data providers. - CScriptCheck check2(coin.out, tx, i, + CScriptCheck check2(txdata.m_spent_outputs[i], tx, i, flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheSigStore, &txdata); if (check2()) return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError()))); @@ -1689,6 +1695,11 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consens flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY; } + // Start enforcing Taproot using versionbits logic. + if (VersionBitsState(pindex->pprev, consensusparams, Consensus::DEPLOYMENT_TAPROOT, versionbitscache) == ThresholdState::ACTIVE) { + flags |= SCRIPT_VERIFY_TAPROOT; + } + // Start enforcing BIP147 NULLDUMMY (activated simultaneously with segwit) if (IsWitnessEnabled(pindex->pprev, consensusparams)) { flags |= SCRIPT_VERIFY_NULLDUMMY; @@ -1897,7 +1908,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl int64_t nSigOpsCost = 0; blockundo.vtxundo.reserve(block.vtx.size() - 1); std::vector txdata; - txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated + txdata.resize(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated for (unsigned int i = 0; i < block.vtx.size(); i++) { const CTransaction &tx = *(block.vtx[i]); @@ -1947,7 +1958,6 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): too many sigops"), REJECT_INVALID, "bad-blk-sigops"); - txdata.emplace_back(tx); if (!tx.IsCoinBase()) { std::vector vChecks; diff --git a/src/versionbitsinfo.cpp b/src/versionbitsinfo.cpp index 82df92ac90ae..21bd8e4c2a7c 100644 --- a/src/versionbitsinfo.cpp +++ b/src/versionbitsinfo.cpp @@ -11,4 +11,8 @@ const struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_B /*.name =*/ "testdummy", /*.gbt_force =*/ true, }, + { + /*.name =*/ "taproot", + /*.gbt_force =*/ true, + }, }; diff --git a/test/functional/feature_taproot.py b/test/functional/feature_taproot.py new file mode 100755 index 000000000000..9d5e3299f6ad --- /dev/null +++ b/test/functional/feature_taproot.py @@ -0,0 +1,443 @@ +#!/usr/bin/env python3 +# Copyright (c) 2019 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# Test taproot softfork. + +from test_framework.blocktools import create_coinbase, create_block, create_transaction, add_witness_commitment +from test_framework.messages import CTransaction, CTxIn, CTxOut, COutPoint, CTxInWitness +from test_framework.script import CScript, TaprootSignatureHash, taproot_construct, GetP2SH, OP_0, OP_1, OP_CHECKSIG, OP_CHECKSIGVERIFY, OP_CHECKSIGADD, OP_IF, OP_CODESEPARATOR, OP_ELSE, OP_ENDIF, OP_DROP, DEFAULT_TAPSCRIPT_VER, SIGHASH_SINGLE, is_op_success, CScriptOp, OP_RETURN, OP_VERIF, OP_RESERVED, OP_1NEGATE, OP_EQUAL, MAX_SCRIPT_ELEMENT_SIZE, LOCKTIME_THRESHOLD, ANNEX_TAG +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal, assert_raises_rpc_error, hex_str_to_bytes +from test_framework.key import ECKey +from test_framework.address import program_to_witness, script_to_p2sh +from binascii import hexlify +from hashlib import sha256 +from io import BytesIO +import random +import struct + +EMPTYWITNESS_ERROR = "non-mandatory-script-verify-flag (Witness program was passed an empty witness) (code 64)" +INVALIDKEYPATHSIG_ERROR = "non-mandatory-script-verify-flag (Invalid signature for taproot key path spending) (code 64)" +UNKNOWNWITNESS_ERROR = "non-mandatory-script-verify-flag (Witness version reserved for soft-fork upgrades) (code 64)" + +DUST_LIMIT = 600 +MIN_FEE = 5000 + +def tx_from_hex(hexstring): + tx = CTransaction() + f = BytesIO(hex_str_to_bytes(hexstring)) + tx.deserialize(f) + return tx + +def get_taproot_bech32(info): + if isinstance(info, tuple): + info = info[0] + return program_to_witness(1, info[2:]) + +def get_taproot_p2sh(info): + return script_to_p2sh(info[0]) + +def random_op_success(): + ret = 0 + while (not is_op_success(ret)): + ret = random.randint(0x50, 0xfe) + return CScriptOp(ret) + +def random_unknown_tapscript_ver(no_annex_tag=True): + ret = DEFAULT_TAPSCRIPT_VER + while (ret == DEFAULT_TAPSCRIPT_VER or (no_annex_tag and ret == (ANNEX_TAG & 0xfe))): + ret = random.randrange(128) * 2 + return ret + +def random_bytes(n): + return bytes(random.getrandbits(8) for i in range(n)) + +def random_script(size, no_success = True): + ret = bytes() + while (len(ret) < size): + remain = size - len(ret) + opcode = random.randrange(256) + while (no_success and is_op_success(opcode)): + opcode = random.randrange(256) + if opcode == 0 or opcode >= OP_1NEGATE: + ret += bytes([opcode]) + elif opcode <= 75 and opcode <= remain - 1: + ret += bytes([opcode]) + random_bytes(opcode) + elif opcode == 76 and remain >= 2: + pushsize = random.randint(0, min(0xff, remain - 2)) + ret += bytes([opcode]) + bytes([pushsize]) + random_bytes(pushsize) + elif opcode == 77 and remain >= 3: + pushsize = random.randint(0, min(0xffff, remain - 3)) + ret += bytes([opcode]) + struct.pack(b'= 5: + pushsize = random.randint(0, min(0xffffffff, remain - 5)) + ret += bytes([opcode]) + struct.pack(b' 0 + ret = bytes() + opcode = 78 + if size <= 75: + opcode = random.randint(75, 78) + elif size <= 255: + opcode = random.randint(76, 78) + elif size <= 0xffff: + opcode = random.randint(77, 78) + if opcode == 75: + ret = bytes([size]) + random_bytes(size - 1) + elif opcode == 76: + ret = bytes([opcode]) + bytes([size]) + random_bytes(size - 2) + elif opcode == 77: + ret = bytes([opcode]) + struct.pack(b'= size + return ret[:size] + +def random_checksig_style(pubkey): + opcode = random.choice([OP_CHECKSIG, OP_CHECKSIGVERIFY, OP_CHECKSIGADD]) + if (opcode == OP_CHECKSIGVERIFY): + ret = CScript([pubkey, opcode, OP_1]) + elif (opcode == OP_CHECKSIGADD): + num = random.choice([0, 0x7fffffff, -0x7fffffff]) + ret = CScript([num, pubkey, opcode, num+1, OP_EQUAL]) + else: + ret = CScript([pubkey, opcode]) + return bytes(ret) + +def damage_bytes(b): + return (int.from_bytes(b, 'big') ^ (1 << random.randrange(len(b)*8))).to_bytes(len(b), 'big') + +def spend_single_sig(tx, input_index, spent_utxos, info, p2sh, key, annex=None, hashtype=0, prefix=[], suffix=[], script=None, pos=-1, damage=False): + ht = hashtype + + damage_type = random.randrange(5) if damage else -1 + ''' + * 0. bit flip the sighash + * 1. bit flip the signature + * If the expected hashtype is 0: + -- 2. append a 0 to the signature + -- 3. append a random value of 1-255 to the signature + * If the expected hashtype is not 0: + -- 2. do not append hashtype to the signature + -- 3. append a random incorrect value of 0-255 to the signature + * 4. extra witness element + ''' + + # Taproot key path spend: tweak key + if script is None: + key = key.tweak_add(info[1]) + assert(key is not None) + # Change SIGHASH_SINGLE into SIGHASH_ALL if no corresponding output + if (ht & 3 == SIGHASH_SINGLE and input_index >= len(tx.vout)): + ht ^= 2 + # Compute sighash + if script: + sighash = TaprootSignatureHash(tx, spent_utxos, ht, input_index, scriptpath = True, tapscript = script, codeseparator_pos = pos, annex = annex) + else: + sighash = TaprootSignatureHash(tx, spent_utxos, ht, input_index, scriptpath = False, annex = annex) + if damage_type == 0: + sighash = damage_bytes(sighash) + # Compute signature + sig = key.sign_schnorr(sighash) + if damage_type == 1: + sig = damage_bytes(sig) + if damage_type == 2: + if ht == 0: + sig += bytes([0]) + elif damage_type == 3: + random_ht = ht + while random_ht == ht: + random_ht = random.randrange(256) + sig += bytes([random_ht]) + elif ht > 0: + sig += bytes([ht]) + # Construct witness + ret = prefix + [sig] + suffix + if script is not None: + ret += [script, info[2][script]] + if annex is not None: + ret += [annex] + if damage_type == 4: + ret = [random_bytes(random.randrange(5))] + ret + tx.wit.vtxinwit[input_index].scriptWitness.stack = ret + # Construct P2SH redeemscript + if p2sh: + tx.vin[input_index].scriptSig = CScript([info[0]]) + +def spend_alwaysvalid(tx, input_index, info, p2sh, script, annex=None, damage=False): + if isinstance(script, tuple): + version, script = script + ret = [script, info[2][script]] + if damage: + # With 50% chance, we bit flip the script (unless the script is an empty vector) + # With 50% chance, we bit flip the control block + if random.choice([True, False]) or len(ret[0]) == 0: + # Annex is always required for tapscript version 0x50 + # Unless the original version is 0x50, we couldn't convert it to 0x50 without using annex + tmp = damage_bytes(ret[1]) + while annex is None and tmp[0] == ANNEX_TAG and ret[1][0] != ANNEX_TAG: + tmp = damage_bytes(ret[1]) + ret[1] = tmp + else: + ret[0] = damage_bytes(ret[0]) + if annex is not None: + ret += [annex] + # Randomly add input witness + if random.choice([True, False]): + for i in range(random.randint(1, 10)): + ret = [random_bytes(random.randint(0, MAX_SCRIPT_ELEMENT_SIZE*2))] + ret + tx.wit.vtxinwit[input_index].scriptWitness.stack = ret + # Construct P2SH redeemscript + if p2sh: + tx.vin[input_index].scriptSig = CScript([info[0]]) + +def spender_sighash_mutation(spenders, info, p2sh, comment, standard=True, **kwargs): + spk = info[0] + addr = get_taproot_bech32(info) + if p2sh: + spk = GetP2SH(spk) + addr = get_taproot_p2sh(info) + def fn(t, i, u, v): + return spend_single_sig(t, i, u, damage=not v, info=info, p2sh=p2sh, **kwargs) + spenders.append((spk, addr, comment, standard, fn)) + +def spender_alwaysvalid(spenders, info, p2sh, comment, **kwargs): + spk = info[0] + addr = get_taproot_bech32(info) + if p2sh: + spk = GetP2SH(spk) + addr = get_taproot_p2sh(info) + def fn(t, i, u, v): + return spend_alwaysvalid(t, i, damage=not v, info=info, p2sh=p2sh, **kwargs) + spenders.append((spk, addr, comment, False, fn)) + +class TAPROOTTest(BitcoinTestFramework): + + def set_test_params(self): + self.num_nodes = 1 + self.setup_clean_chain = True + self.extra_args = [["-whitelist=127.0.0.1", "-acceptnonstdtxn=0", "-par=1"]] + + def block_submit(self, node, txs, msg, cb_pubkey=None, fees=0, witness=False, accept=False): + block = create_block(self.tip, create_coinbase(self.lastblockheight + 1, pubkey=cb_pubkey, fees=fees), self.lastblocktime + 1) + block.nVersion = 4 + for tx in txs: + tx.rehash() + block.vtx.append(tx) + block.hashMerkleRoot = block.calc_merkle_root() + witness and add_witness_commitment(block) + block.rehash() + block.solve() + node.submitblock(block.serialize(True).hex()) + if (accept): + assert node.getbestblockhash() == block.hash, "Failed to accept: " + msg + self.tip = block.sha256 + self.lastblockhash = block.hash + self.lastblocktime += 1 + self.lastblockheight += 1 + else: + assert node.getbestblockhash() == self.lastblockhash, "Failed to reject: " + msg + + def test_spenders(self, spenders, input_counts): + """Run randomized tests with a number of "spenders". + + Each spender is a tuple of: + - A scriptPubKey (CScript) + - An address for that scriptPubKey (string) + - A comment describing the test (string) + - Whether the spending (on itself) is expected to be standard (bool) + - A lambda taking as inputs: + - A transaction to sign (CTransaction) + - An input position (int) + - The spent UTXOs by this transaction (list of CTxOut) + - Whether to produce a valid spend (bool) + + Each spender embodies a test; in a large randomized test, it is verified + that toggling the valid argument to each lambda toggles the validity of + the transaction. This is accomplished by constructing transactions consisting + of all valid inputs, except one invalid one. + """ + + # Construct a UTXO to spend for each of the spenders + self.nodes[0].generate(110) + bal = self.nodes[0].getbalance() * 3 / (4*len(spenders)) + random.shuffle(spenders) + num_spenders = len(spenders) + utxos = [] + while len(spenders): + # Create the necessary outputs in multiple transactions, as sPKs may be repeated (which sendmany does not support) + outputs = {} + new_spenders = [] + batch = [] + for spender in spenders: + addr = spender[1] + if addr in outputs: + new_spenders.append(spender) + else: + amount = random.randrange(int(bal * 95000000), int(bal * 105000000)) + outputs[addr] = amount / 100000000 + batch.append(spender) + self.log.info("Constructing %i UTXOs for spending tests" % len(batch)) + tx = tx_from_hex(self.nodes[0].getrawtransaction(self.nodes[0].sendmany("", outputs))) + tx.rehash() + spenders = new_spenders + random.shuffle(spenders) + + # Map created UTXOs back to the spenders they were created for + for n, out in enumerate(tx.vout): + for spender in batch: + if out.scriptPubKey == spender[0]: + utxos.append((COutPoint(tx.sha256, n), out, spender)) + break + assert(len(utxos) == num_spenders) + random.shuffle(utxos) + self.nodes[0].generate(1) + + # Construct a bunch of sPKs that send coins back to the host wallet + self.log.info("Constructing 100 addresses for returning coins") + host_spks = [] + host_pubkeys = [] + for i in range(100): + addr = self.nodes[0].getnewaddress(address_type=random.choice(["legacy", "p2sh-segwit", "bech32"])) + info = self.nodes[0].getaddressinfo(addr) + spk = hex_str_to_bytes(info['scriptPubKey']) + host_spks.append(spk) + host_pubkeys.append(hex_str_to_bytes(info['pubkey'])) + + # Pick random subsets of UTXOs to construct transactions with + self.lastblockhash = self.nodes[0].getbestblockhash() + self.tip = int("0x" + self.lastblockhash, 0) + block = self.nodes[0].getblock(self.lastblockhash) + self.lastblockheight = block['height'] + self.lastblocktime = block['time'] + while len(utxos): + tx = CTransaction() + tx.nVersion = random.choice([1, 2, random.randint(-0x80000000,0x7fffffff)]) + min_sequence = (tx.nVersion != 1 and tx.nVersion != 0) * 0x80000000 # The minimum sequence number to disable relative locktime + if random.choice([True, False]): + tx.nLockTime = random.randrange(LOCKTIME_THRESHOLD, self.lastblocktime - 7200) # all absolute locktimes in the past + else: + tx.nLockTime = random.randrange(self.lastblockheight+1) # all block heights in the past + + # Pick 1 to 4 UTXOs to construct transaction inputs + acceptable_input_counts = [cnt for cnt in input_counts if cnt <= len(utxos)] + while True: + inputs = random.choice(acceptable_input_counts) + remaining = len(utxos) - inputs + if remaining == 0 or remaining >= max(input_counts) or remaining in input_counts: + break + input_utxos = utxos[-inputs:] + utxos = utxos[:-inputs] + fee = random.randrange(MIN_FEE * 2, MIN_FEE * 4) # 10000-20000 sat fee + in_value = sum(utxo[1].nValue for utxo in input_utxos) - fee + tx.vin = [CTxIn(outpoint = input_utxos[i][0], nSequence = random.randint(min_sequence, 0xffffffff)) for i in range(inputs)] + tx.wit.vtxinwit = [CTxInWitness() for i in range(inputs)] + self.log.info("Test: %s" % (", ".join(utxo[2][2] for utxo in input_utxos))) + + # Add 1 to 4 outputs + outputs = random.choice([1,2,3,4]) + assert in_value >= 0 and fee - outputs * DUST_LIMIT >= MIN_FEE + for i in range(outputs): + tx.vout.append(CTxOut()) + if in_value <= DUST_LIMIT: + tx.vout[-1].nValue = DUST_LIMIT + elif i < outputs - 1: + tx.vout[-1].nValue = in_value + else: + tx.vout[-1].nValue = random.randint(DUST_LIMIT, in_value) + in_value -= tx.vout[-1].nValue + tx.vout[-1].scriptPubKey = random.choice(host_spks) + fee += in_value + assert(fee >= 0) + + # For each inputs, make it fail once; then succeed once + for fail_input in range(inputs + 1): + # Wipe scriptSig/witness + for i in range(inputs): + tx.vin[i].scriptSig = CScript() + tx.wit.vtxinwit[i] = CTxInWitness() + # Fill inputs/witnesses + for i in range(inputs): + fn = input_utxos[i][2][4] + fn(tx, i, [utxo[1] for utxo in input_utxos], i != fail_input) + # Submit to mempool to check standardness + standard = fail_input == inputs and all(utxo[2][3] for utxo in input_utxos) and tx.nVersion >= 1 and tx.nVersion <= 2 + if standard: + self.nodes[0].sendrawtransaction(tx.serialize().hex(), 0) + assert(self.nodes[0].getmempoolentry(tx.hash) is not None) + else: + assert_raises_rpc_error(-26, None, self.nodes[0].sendrawtransaction, tx.serialize().hex(), 0) + # Submit in a block + tx.rehash() + msg = ','.join(utxo[2][2] + ("*" if n == fail_input else "") for n, utxo in enumerate(input_utxos)) + self.block_submit(self.nodes[0], [tx], msg, witness=True, accept=fail_input == inputs, cb_pubkey=random.choice(host_pubkeys), fees=fee) + + def run_test(self): + VALID_SIGHASHES = [0,1,2,3,0x81,0x82,0x83] + spenders = [] + + for p2sh in [False, True]: + random_annex = bytes([ANNEX_TAG]) + random_bytes(random.randrange(0, 5)) + for annex in [None, random_annex]: + standard = annex is None + sec1, sec2 = ECKey(), ECKey() + sec1.generate() + sec2.generate() + pub1, pub2 = sec1.get_pubkey(), sec2.get_pubkey() + + # Sighash mutation tests + for hashtype in VALID_SIGHASHES: + # Pure pubkey + info = taproot_construct(pub1, []) + spender_sighash_mutation(spenders, info, p2sh, "sighash/pk#pk", key=sec1, hashtype=hashtype, annex=annex, standard=standard) + # Pubkey/P2PK script combination + scripts = [CScript(random_checksig_style(pub2.get_bytes()))] + info = taproot_construct(pub1, scripts) + spender_sighash_mutation(spenders, info, p2sh, "sighash/p2pk#pk", key=sec1, hashtype=hashtype, annex=annex, standard=standard) + spender_sighash_mutation(spenders, info, p2sh, "sighash/p2pk#s0", script=scripts[0], key=sec2, hashtype=hashtype, annex=annex, standard=standard) + # More complex script structure + scripts = [ + CScript(random_checksig_style(pub2.get_bytes()) + bytes([OP_CODESEPARATOR])), # codesep after checksig + CScript(bytes([OP_CODESEPARATOR]) + random_checksig_style(pub2.get_bytes())), # codesep before checksig + CScript([bytes([1,2,3]), OP_DROP, OP_IF, OP_CODESEPARATOR, pub1.get_bytes(), OP_ELSE, OP_CODESEPARATOR, pub2.get_bytes(), OP_ENDIF, OP_CHECKSIG]), # branch dependent codesep + ] + info = taproot_construct(pub1, scripts) + spender_sighash_mutation(spenders, info, p2sh, "sighash/codesep#pk", key=sec1, hashtype=hashtype, annex=annex, standard=standard) + spender_sighash_mutation(spenders, info, p2sh, "sighash/codesep#s0", script=scripts[0], key=sec2, hashtype=hashtype, annex=annex, standard=standard) + spender_sighash_mutation(spenders, info, p2sh, "sighash/codesep#s1", script=scripts[1], key=sec2, hashtype=hashtype, annex=annex, pos=0, standard=standard) + spender_sighash_mutation(spenders, info, p2sh, "sighash/codesep#s2a", script=scripts[2], key=sec1, hashtype=hashtype, annex=annex, pos=3, suffix=[bytes([1])], standard=standard) + spender_sighash_mutation(spenders, info, p2sh, "sighash/codesep#s2b", script=scripts[2], key=sec2, hashtype=hashtype, annex=annex, pos=6, suffix=[bytes([])], standard=standard) + + # OP_SUCCESSx and unknown tapscript versions + scripts = [ + CScript([random_op_success()]), + CScript([OP_0, OP_IF, random_op_success(), OP_ENDIF, OP_RETURN]), + CScript([random_op_success(), OP_VERIF]), + CScript(random_script(10000) + bytes([random_op_success()]) + random_invalid_push(random.randint(1,10))), + (random_unknown_tapscript_ver(), CScript([OP_RETURN])), + (random_unknown_tapscript_ver(), CScript(random_script(10000) + random_invalid_push(random.randint(1,10)))), + (ANNEX_TAG & 0xfe, CScript()), + ] + info = taproot_construct(pub1, scripts) + spender_sighash_mutation(spenders, info, p2sh, "alwaysvalid/pk", key=sec1, hashtype=random.choice(VALID_SIGHASHES), annex=annex, standard=standard) + spender_alwaysvalid(spenders, info, p2sh, "alwaysvalid/success", script=scripts[0], annex=annex) + spender_alwaysvalid(spenders, info, p2sh, "alwaysvalid/success#if", script=scripts[1], annex=annex) + spender_alwaysvalid(spenders, info, p2sh, "alwaysvalid/success#verif", script=scripts[2], annex=annex) + spender_alwaysvalid(spenders, info, p2sh, "alwaysvalid/success#10000+", script=scripts[3], annex=annex) + spender_alwaysvalid(spenders, info, p2sh, "alwaysvalid/unknownversion#return", script=scripts[4], annex=annex) + spender_alwaysvalid(spenders, info, p2sh, "alwaysvalid/unknownversion#10000+", script=scripts[5], annex=annex) + if (info[2][scripts[6][1]][0] != ANNEX_TAG or annex is not None): + # Annex is mandatory for control block with version 0x50 + spender_alwaysvalid(spenders, info, p2sh, "alwaysvalid/unknownversion#fe", script=scripts[6], annex=annex) + + # Run all tests once with individual inputs, once with groups of inputs + self.test_spenders(spenders, input_counts=[1]) + self.test_spenders(spenders, input_counts=[2,3,4]) + + +if __name__ == '__main__': + TAPROOTTest().main() diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index 98f6b1d71ddb..8218671b2cdb 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -89,6 +89,12 @@ MAX_SIGOP_COST = 80000 SEGWIT_HEIGHT = 120 +MAX_STANDARD_WITNESS_INPUT_STACK_ITEMS = 210 +MAX_STANDARD_WITNESS_INPUT_STACK_ITEM_SIZE = 80 +MAX_STANDARD_WITNESS_SCRIPT_SIZE = 7100 +# Extra restrictions make tests easier +assert MAX_STANDARD_WITNESS_INPUT_STACK_ITEMS < 403 and (MAX_STANDARD_WITNESS_INPUT_STACK_ITEMS % 2) == 0 +assert MAX_STANDARD_WITNESS_SCRIPT_SIZE % 50 == 0 class UTXO(): """Used to keep track of anyone-can-spend outputs that we can use in the tests.""" @@ -1797,10 +1803,12 @@ def test_non_standard_witness(self): # Create scripts for tests scripts = [] - scripts.append(CScript([OP_DROP] * 100)) - scripts.append(CScript([OP_DROP] * 99)) - scripts.append(CScript([pad * 59] * 59 + [OP_DROP] * 60)) - scripts.append(CScript([pad * 59] * 59 + [OP_DROP] * 61)) + scripts.append(CScript([OP_2DROP] * (MAX_STANDARD_WITNESS_INPUT_STACK_ITEMS // 2))) + scripts.append(CScript([OP_2DROP] * (MAX_STANDARD_WITNESS_INPUT_STACK_ITEMS // 2 - 1) + [OP_DROP])) + scripts.append(CScript([pad * 48] * (MAX_STANDARD_WITNESS_SCRIPT_SIZE // 50) + [OP_DROP] * (MAX_STANDARD_WITNESS_SCRIPT_SIZE // 50))) + scripts.append(CScript([pad * 48] * (MAX_STANDARD_WITNESS_SCRIPT_SIZE // 50) + [OP_DROP] * (MAX_STANDARD_WITNESS_SCRIPT_SIZE // 50 + 1))) + assert len(scripts[2]) == MAX_STANDARD_WITNESS_SCRIPT_SIZE + assert len(scripts[3]) == MAX_STANDARD_WITNESS_SCRIPT_SIZE + 1 p2wsh_scripts = [] @@ -1840,45 +1848,45 @@ def test_non_standard_witness(self): p2sh_txs.append(p2sh_tx) # Testing native P2WSH - # Witness stack size, excluding witnessScript, over 100 is non-standard - p2wsh_txs[0].wit.vtxinwit[0].scriptWitness.stack = [pad] * 101 + [scripts[0]] + # Witness stack size, excluding witnessScript, over MAX_STANDARD_WITNESS_INPUT_STACK_ITEMS is non-standard + p2wsh_txs[0].wit.vtxinwit[0].scriptWitness.stack = [pad] * (MAX_STANDARD_WITNESS_INPUT_STACK_ITEMS + 1) + [scripts[0]] test_transaction_acceptance(self.nodes[1], self.std_node, p2wsh_txs[0], True, False, 'bad-witness-nonstandard') # Non-standard nodes should accept test_transaction_acceptance(self.nodes[0], self.test_node, p2wsh_txs[0], True, True) - # Stack element size over 80 bytes is non-standard - p2wsh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 81] * 100 + [scripts[1]] + # Stack element size over MAX_STANDARD_WITNESS_INPUT_STACK_ITEM_SIZE bytes is non-standard + p2wsh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * (MAX_STANDARD_WITNESS_INPUT_STACK_ITEM_SIZE + 1)] * MAX_STANDARD_WITNESS_INPUT_STACK_ITEMS + [scripts[1]] test_transaction_acceptance(self.nodes[1], self.std_node, p2wsh_txs[1], True, False, 'bad-witness-nonstandard') # Non-standard nodes should accept test_transaction_acceptance(self.nodes[0], self.test_node, p2wsh_txs[1], True, True) - # Standard nodes should accept if element size is not over 80 bytes - p2wsh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 80] * 100 + [scripts[1]] + # Standard nodes should accept if element size is not over MAX_STANDARD_WITNESS_INPUT_STACK_ITEM_SIZE + p2wsh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * MAX_STANDARD_WITNESS_INPUT_STACK_ITEM_SIZE] * MAX_STANDARD_WITNESS_INPUT_STACK_ITEMS + [scripts[1]] test_transaction_acceptance(self.nodes[1], self.std_node, p2wsh_txs[1], True, True) - # witnessScript size at 3600 bytes is standard - p2wsh_txs[2].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, scripts[2]] + # witnessScript size at 7100 bytes is standard + p2wsh_txs[2].wit.vtxinwit[0].scriptWitness.stack = [pad, scripts[2]] test_transaction_acceptance(self.nodes[0], self.test_node, p2wsh_txs[2], True, True) test_transaction_acceptance(self.nodes[1], self.std_node, p2wsh_txs[2], True, True) - # witnessScript size at 3601 bytes is non-standard - p2wsh_txs[3].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, pad, scripts[3]] + # witnessScript size at 7101 bytes is non-standard + p2wsh_txs[3].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, scripts[3]] test_transaction_acceptance(self.nodes[1], self.std_node, p2wsh_txs[3], True, False, 'bad-witness-nonstandard') # Non-standard nodes should accept test_transaction_acceptance(self.nodes[0], self.test_node, p2wsh_txs[3], True, True) # Repeating the same tests with P2SH-P2WSH - p2sh_txs[0].wit.vtxinwit[0].scriptWitness.stack = [pad] * 101 + [scripts[0]] + p2sh_txs[0].wit.vtxinwit[0].scriptWitness.stack = [pad] * (MAX_STANDARD_WITNESS_INPUT_STACK_ITEMS + 1) + [scripts[0]] test_transaction_acceptance(self.nodes[1], self.std_node, p2sh_txs[0], True, False, 'bad-witness-nonstandard') test_transaction_acceptance(self.nodes[0], self.test_node, p2sh_txs[0], True, True) - p2sh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 81] * 100 + [scripts[1]] + p2sh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * (MAX_STANDARD_WITNESS_INPUT_STACK_ITEM_SIZE + 1)] * MAX_STANDARD_WITNESS_INPUT_STACK_ITEMS + [scripts[1]] test_transaction_acceptance(self.nodes[1], self.std_node, p2sh_txs[1], True, False, 'bad-witness-nonstandard') test_transaction_acceptance(self.nodes[0], self.test_node, p2sh_txs[1], True, True) - p2sh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 80] * 100 + [scripts[1]] + p2sh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * MAX_STANDARD_WITNESS_INPUT_STACK_ITEM_SIZE] * MAX_STANDARD_WITNESS_INPUT_STACK_ITEMS + [scripts[1]] test_transaction_acceptance(self.nodes[1], self.std_node, p2sh_txs[1], True, True) - p2sh_txs[2].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, scripts[2]] + p2sh_txs[2].wit.vtxinwit[0].scriptWitness.stack = [pad, scripts[2]] test_transaction_acceptance(self.nodes[0], self.test_node, p2sh_txs[2], True, True) test_transaction_acceptance(self.nodes[1], self.std_node, p2sh_txs[2], True, True) - p2sh_txs[3].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, pad, scripts[3]] + p2sh_txs[3].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, scripts[3]] test_transaction_acceptance(self.nodes[1], self.std_node, p2sh_txs[3], True, False, 'bad-witness-nonstandard') test_transaction_acceptance(self.nodes[0], self.test_node, p2sh_txs[3], True, True) diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py index d741b00ba0a7..2c1a73a607e0 100644 --- a/test/functional/test_framework/blocktools.py +++ b/test/functional/test_framework/blocktools.py @@ -99,8 +99,8 @@ def script_BIP34_coinbase_height(height): return CScript([CScriptNum(height)]) -def create_coinbase(height, pubkey=None): - """Create a coinbase transaction, assuming no miner fees. +def create_coinbase(height, pubkey=None, fees=0): + """Create a coinbase transaction. If pubkey is passed in, the coinbase output will be a P2PK output; otherwise an anyone-can-spend output.""" @@ -110,6 +110,7 @@ def create_coinbase(height, pubkey=None): coinbaseoutput.nValue = 50 * COIN halvings = int(height / 150) # regtest coinbaseoutput.nValue >>= halvings + coinbaseoutput.nValue += fees if (pubkey is not None): coinbaseoutput.scriptPubKey = CScript([pubkey, OP_CHECKSIG]) else: diff --git a/test/functional/test_framework/key.py b/test/functional/test_framework/key.py index 912c0ca978e3..b3c283623692 100644 --- a/test/functional/test_framework/key.py +++ b/test/functional/test_framework/key.py @@ -7,6 +7,7 @@ keys, and is trivially vulnerable to side channel attacks. Do not use for anything but tests.""" import random +import hashlib def modinv(a, n): """Compute the modular inverse of a modulo n @@ -212,7 +213,8 @@ def mul(self, ps): r = self.add(r, p) return r -SECP256K1 = EllipticCurve(2**256 - 2**32 - 977, 0, 7) +SECP256K1_FIELD_SIZE = 2**256 - 2**32 - 977 +SECP256K1 = EllipticCurve(SECP256K1_FIELD_SIZE, 0, 7) SECP256K1_G = (0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798, 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8, 1) SECP256K1_ORDER = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 SECP256K1_ORDER_HALF = SECP256K1_ORDER // 2 @@ -322,6 +324,38 @@ def verify_ecdsa(self, sig, msg, low_s=True): return False return True + def verify_schnorr(self, sig, msg): + assert(len(msg) == 32) + assert(len(sig) == 64) + assert(self.valid) + assert(self.compressed) + r = int.from_bytes(sig[0:32], 'big') + if r >= SECP256K1_FIELD_SIZE: + return False + s = int.from_bytes(sig[32:64], 'big') + if s >= SECP256K1_ORDER: + return False + e = int.from_bytes(hashlib.sha256(sig[0:32] + self.get_bytes() + msg).digest(), 'big') % SECP256K1_ORDER + R = SECP256K1.mul([(SECP256K1_G, s), (self.p, SECP256K1_ORDER - e)]) + if R[2] == 0 or jacobi_symbol(R[1] * R[2], SECP256K1_FIELD_SIZE) != 1 or ((r * R[2] * R[2]) % SECP256K1_FIELD_SIZE) != R[0]: + return False + return True + + def tweak_add(self, tweak): + assert(self.valid) + assert(len(tweak) == 32) + t = int.from_bytes(tweak, 'big') + if t >= SECP256K1_ORDER: + return None + tweaked = SECP256K1.affine(SECP256K1.mul([(self.p, 1), (SECP256K1_G, t)])) + if tweaked is None: + return None + ret = ECPubKey() + ret.p = tweaked + ret.valid = True + ret.compressed = self.compressed + return ret + class ECKey(): """A secp256k1 private key""" @@ -384,3 +418,29 @@ def sign_ecdsa(self, msg, low_s=True): rb = r.to_bytes((r.bit_length() + 8) // 8, 'big') sb = s.to_bytes((s.bit_length() + 8) // 8, 'big') return b'\x30' + bytes([4 + len(rb) + len(sb), 2, len(rb)]) + rb + bytes([2, len(sb)]) + sb + + def sign_schnorr(self, msg): + """Construct a bip-schnorr compatible signature with this key.""" + assert(self.valid) + assert(self.compressed) + assert(len(msg) == 32) + kp = int.from_bytes(hashlib.sha256(self.get_bytes() + msg).digest(), 'big') % SECP256K1_ORDER + assert(kp != 0) + R = SECP256K1.affine(SECP256K1.mul([(SECP256K1_G, kp)])) + k = kp if jacobi_symbol(R[1], SECP256K1_FIELD_SIZE) == 1 else SECP256K1_ORDER - kp + e = int.from_bytes(hashlib.sha256(R[0].to_bytes(32, 'big') + self.get_pubkey().get_bytes() + msg).digest(), 'big') % SECP256K1_ORDER + return R[0].to_bytes(32, 'big') + ((k + e*self.secret) % SECP256K1_ORDER).to_bytes(32, 'big') + + def tweak_add(self, tweak): + """Return a tweaked version of this private key.""" + assert(self.valid) + assert(len(tweak) == 32) + t = int.from_bytes(tweak, 'big') + if t >= SECP256K1_ORDER: + return None + tweaked = (self.secret + t) % SECP256K1_ORDER + if tweaked == 0: + return None + ret = ECKey() + ret.set(tweaked.to_bytes(32, 'big'), self.compressed) + return ret diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py index 384062b8084f..962d2687f488 100644 --- a/test/functional/test_framework/script.py +++ b/test/functional/test_framework/script.py @@ -7,7 +7,8 @@ This file is modified from python-bitcoinlib. """ -from .messages import CTransaction, CTxOut, sha256, hash256, uint256_from_str, ser_uint256, ser_string +from .messages import CTransaction, CTxOut, sha256, hash256, uint256_from_str, ser_uint256, ser_string, CTxInWitness +from .key import ECKey, ECPubKey import hashlib import struct @@ -15,9 +16,14 @@ from .bignum import bn2vch MAX_SCRIPT_ELEMENT_SIZE = 520 +LOCKTIME_THRESHOLD = 500000000 +ANNEX_TAG = 0x50 OPCODE_NAMES = {} +DEFAULT_TAPSCRIPT_VER = 0xc0 +TAPROOT_VER = 0 + def hash160(s): return hashlib.new('ripemd160', sha256(s)).digest() @@ -223,11 +229,8 @@ def __new__(cls, n): OP_NOP9 = CScriptOp(0xb8) OP_NOP10 = CScriptOp(0xb9) -# template matching params -OP_SMALLINTEGER = CScriptOp(0xfa) -OP_PUBKEYS = CScriptOp(0xfb) -OP_PUBKEYHASH = CScriptOp(0xfd) -OP_PUBKEY = CScriptOp(0xfe) +# tapscript +OP_CHECKSIGADD = CScriptOp(0xba) OP_INVALIDOPCODE = CScriptOp(0xff) @@ -343,10 +346,7 @@ def __new__(cls, n): OP_NOP8 : 'OP_NOP8', OP_NOP9 : 'OP_NOP9', OP_NOP10 : 'OP_NOP10', - OP_SMALLINTEGER : 'OP_SMALLINTEGER', - OP_PUBKEYS : 'OP_PUBKEYS', - OP_PUBKEYHASH : 'OP_PUBKEYHASH', - OP_PUBKEY : 'OP_PUBKEY', + OP_CHECKSIGADD : 'OP_CHECKSIGADD', OP_INVALIDOPCODE : 'OP_INVALIDOPCODE', }) @@ -607,6 +607,20 @@ def FindAndDelete(script, sig): r += script[last_sop_idx:] return CScript(r) +def IsPayToScriptHash(script): + return len(script) == 23 and script[0] == OP_HASH160 and script[1] == 20 and script[22] == OP_EQUAL + +def IsPayToTaproot(script): + return len(script) == 35 and script[0] == OP_1 and script[1] == 33 and script[2] >= 0 and script[2] <= 1 + +def TaggedHash(tag, data): + ss = sha256(tag.encode('utf-8')) + ss += ss + ss += data + return sha256(ss) + +def GetP2SH(script): + return CScript([OP_HASH160, hash160(script), OP_EQUAL]) def SignatureHash(script, txTo, inIdx, hashtype): """Consensus-correct SignatureHash @@ -702,3 +716,102 @@ def SegwitVersion1SignatureHash(script, txTo, inIdx, hashtype, amount): ss += struct.pack("= 0 and hash_type <= 3) or (hash_type >= 0x81 and hash_type <= 0x83)) + assert (input_index < len(txTo.vin)) + spk = spent_utxos[input_index].scriptPubKey + ss = bytes([0, hash_type]) # epoch, hash_type + ss += struct.pack(" 0) + assert (codeseparator_pos >= -1) + spend_type |= 4 + ss += bytes([spend_type]) + ss += ser_string(spk) + if (hash_type & SIGHASH_ANYONECANPAY): + ss += txTo.vin[input_index].prevout.serialize() + ss += struct.pack("= 0 and version < 0xff and not (version & 1) + data = pubkey.get_bytes() + return bytes([data[0] & 1 | version]) + data[1:] + +def taproot_tree_helper(scripts): + if len(scripts) == 1: + script = scripts[0] + if isinstance(script, list): + return taproot_tree_helper(script) + version = DEFAULT_TAPSCRIPT_VER + if isinstance(script, tuple): + version, script = script + assert isinstance(script, bytes) + h = TaggedHash("TapLeaf", bytes([version & 0xfe]) + ser_string(script)) + return ([(version, script, bytes())], h) + split_pos = len(scripts) // 2 + left, left_h = taproot_tree_helper(scripts[0:split_pos]) + right, right_h = taproot_tree_helper(scripts[split_pos:]) + left = [(version, script, control + right_h) for version, script, control in left] + right = [(version, script, control + left_h) for version, script, control in right] + if right_h < left_h: + right_h, left_h = left_h, right_h + h = TaggedHash("TapBranch", left_h + right_h) + return (left + right, h) + +def taproot_construct(pubkey, scripts=[]): + """Construct a tree of taproot spending conditions + + pubkey: an ECPubKey object for the root pubkey + scripts: a list of items; each item is either: + - a CScript + - a (version, CScript) tuple + - another list of items (with the same structure) + + Returns: script (sPK or redeemScript), tweak, {script:control, ...} + """ + if len(scripts) == 0: + return (CScript([OP_1, GetVersionTaggedPubKey(pubkey, TAPROOT_VER)]), bytes([0 for i in range(32)]), {}) + + ret, h = taproot_tree_helper(scripts) + control_map = dict((script, GetVersionTaggedPubKey(pubkey, version) + control) for version, script, control in ret) + tweak = TaggedHash("TapTweak", pubkey.get_bytes() + h) + tweaked = pubkey.tweak_add(tweak) + return (CScript([OP_1, GetVersionTaggedPubKey(tweaked, TAPROOT_VER)]), tweak, control_map) + +def is_op_success(o): + return o == 0x50 or o == 0x62 or o == 0x89 or o == 0x8a or o == 0x8d or o == 0x8e or (o >= 0x7e and o <= 0x81) or (o >= 0x83 and o <= 0x86) or (o >= 0x95 and o <= 0x99) or (o >= 0xbb and o <= 0xfe) diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index ad5673e03a23..f8a35dc68081 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -148,6 +148,7 @@ 'p2p_mempool.py', 'rpc_setban.py', 'p2p_blocksonly.py', + 'feature_taproot.py', 'mining_prioritisetransaction.py', 'p2p_invalid_locator.py', 'p2p_invalid_block.py',