script/sign: signing support for Miniscripts with hash preimage challenges

Preimages must be externally provided (typically, via a PSBT).
This commit is contained in:
Antoine Poinsot
2021-12-04 14:39:24 +01:00
parent a2f81b6a8f
commit 560e62b1e2
9 changed files with 109 additions and 37 deletions

View File

@@ -382,6 +382,17 @@ static CScript PushAll(const std::vector<valtype>& values)
return result;
}
template<typename M, typename K, typename V>
miniscript::Availability MsLookupHelper(const M& map, const K& key, V& value)
{
auto it = map.find(key);
if (it != map.end()) {
value = it->second;
return miniscript::Availability::YES;
}
return miniscript::Availability::NO;
}
/**
* Context for solving a Miniscript.
* If enough material (access to keys, hash preimages, ..) is given, produces a valid satisfaction.
@@ -443,11 +454,18 @@ struct Satisfier {
//! Hash preimage satisfactions.
// TODO
miniscript::Availability SatSHA256(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const { return miniscript::Availability::NO; }
miniscript::Availability SatRIPEMD160(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const { return miniscript::Availability::NO; }
miniscript::Availability SatHASH256(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const { return miniscript::Availability::NO; }
miniscript::Availability SatHASH160(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const { return miniscript::Availability::NO; }
miniscript::Availability SatSHA256(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const {
return MsLookupHelper(m_sig_data.sha256_preimages, hash, preimage);
}
miniscript::Availability SatRIPEMD160(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const {
return MsLookupHelper(m_sig_data.ripemd160_preimages, hash, preimage);
}
miniscript::Availability SatHASH256(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const {
return MsLookupHelper(m_sig_data.hash256_preimages, hash, preimage);
}
miniscript::Availability SatHASH160(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const {
return MsLookupHelper(m_sig_data.hash160_preimages, hash, preimage);
}
};
bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreator& creator, const CScript& fromPubKey, SignatureData& sigdata)
@@ -645,26 +663,25 @@ void SignatureData::MergeSignatureData(SignatureData sigdata)
signatures.insert(std::make_move_iterator(sigdata.signatures.begin()), std::make_move_iterator(sigdata.signatures.end()));
}
bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType)
bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType, SignatureData& sig_data)
{
assert(nIn < txTo.vin.size());
MutableTransactionSignatureCreator creator(txTo, nIn, amount, nHashType);
SignatureData sigdata;
bool ret = ProduceSignature(provider, creator, fromPubKey, sigdata);
UpdateInput(txTo.vin.at(nIn), sigdata);
bool ret = ProduceSignature(provider, creator, fromPubKey, sig_data);
UpdateInput(txTo.vin.at(nIn), sig_data);
return ret;
}
bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType, SignatureData& sig_data)
{
assert(nIn < txTo.vin.size());
const CTxIn& txin = txTo.vin[nIn];
assert(txin.prevout.n < txFrom.vout.size());
const CTxOut& txout = txFrom.vout[txin.prevout.n];
return SignSignature(provider, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType);
return SignSignature(provider, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType, sig_data);
}
namespace {

View File

@@ -82,6 +82,10 @@ struct SignatureData {
std::vector<CKeyID> missing_sigs; ///< KeyIDs of pubkeys for signatures which could not be found
uint160 missing_redeem_script; ///< ScriptID of the missing redeemScript (if any)
uint256 missing_witness_script; ///< SHA256 of the missing witnessScript (if any)
std::map<std::vector<uint8_t>, std::vector<uint8_t>> sha256_preimages; ///< Mapping from a SHA256 hash to its preimage provided to solve a Script
std::map<std::vector<uint8_t>, std::vector<uint8_t>> hash256_preimages; ///< Mapping from a HASH256 hash to its preimage provided to solve a Script
std::map<std::vector<uint8_t>, std::vector<uint8_t>> ripemd160_preimages; ///< Mapping from a RIPEMD160 hash to its preimage provided to solve a Script
std::map<std::vector<uint8_t>, std::vector<uint8_t>> hash160_preimages; ///< Mapping from a HASH160 hash to its preimage provided to solve a Script
SignatureData() {}
explicit SignatureData(const CScript& script) : scriptSig(script) {}
@@ -91,9 +95,24 @@ struct SignatureData {
/** Produce a script signature using a generic signature creator. */
bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreator& creator, const CScript& scriptPubKey, SignatureData& sigdata);
/** Produce a script signature for a transaction. */
bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType);
bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType);
/**
* Produce a satisfying script (scriptSig or witness).
*
* @param provider Utility containing the information necessary to solve a script.
* @param fromPubKey The script to produce a satisfaction for.
* @param txTo The spending transaction.
* @param nIn The index of the input in `txTo` refering the output being spent.
* @param amount The value of the output being spent.
* @param nHashType Signature hash type.
* @param sig_data Additional data provided to solve a script. Filled with the resulting satisfying
* script and whether the satisfaction is complete.
*
* @return True if the produced script is entirely satisfying `fromPubKey`.
**/
bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo,
unsigned int nIn, const CAmount& amount, int nHashType, SignatureData& sig_data);
bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo,
unsigned int nIn, int nHashType, SignatureData& sig_data);
/** Extract signature data from a transaction input, and insert it. */
SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn, const CTxOut& txout);