mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-31 10:41:08 +00:00
sign: Add CreateMuSig2PartialSig
This commit is contained in:
parent
512b17fc56
commit
bf69442b3f
89
src/key.cpp
89
src/key.cpp
@ -383,6 +383,95 @@ std::vector<uint8_t> CKey::CreateMuSig2Nonce(MuSig2SecNonce& secnonce, const uin
|
||||
return out;
|
||||
}
|
||||
|
||||
std::optional<uint256> CKey::CreateMuSig2PartialSig(const uint256& sighash, const CPubKey& aggregate_pubkey, const std::vector<CPubKey>& pubkeys, const std::map<CPubKey, std::vector<uint8_t>>& pubnonces, MuSig2SecNonce& secnonce, const std::vector<std::pair<uint256, bool>>& tweaks)
|
||||
{
|
||||
secp256k1_keypair keypair;
|
||||
if (!secp256k1_keypair_create(secp256k1_context_sign, &keypair, UCharCast(begin()))) return std::nullopt;
|
||||
|
||||
// Get the keyagg cache and aggregate pubkey
|
||||
secp256k1_musig_keyagg_cache keyagg_cache;
|
||||
if (!MuSig2AggregatePubkeys(pubkeys, keyagg_cache, aggregate_pubkey)) return std::nullopt;
|
||||
|
||||
// Check that there are enough pubnonces
|
||||
if (pubnonces.size() != pubkeys.size()) return std::nullopt;
|
||||
|
||||
// Parse the pubnonces
|
||||
std::vector<std::pair<secp256k1_pubkey, secp256k1_musig_pubnonce>> signers_data;
|
||||
std::vector<const secp256k1_musig_pubnonce*> pubnonce_ptrs;
|
||||
std::optional<size_t> our_pubkey_idx;
|
||||
CPubKey our_pubkey = GetPubKey();
|
||||
for (const CPubKey& part_pk : pubkeys) {
|
||||
const auto& pn_it = pubnonces.find(part_pk);
|
||||
if (pn_it == pubnonces.end()) return std::nullopt;
|
||||
const std::vector<uint8_t> pubnonce = pn_it->second;
|
||||
if (pubnonce.size() != MUSIG2_PUBNONCE_SIZE) return std::nullopt;
|
||||
if (part_pk == our_pubkey) {
|
||||
our_pubkey_idx = signers_data.size();
|
||||
}
|
||||
|
||||
auto& [secp_pk, secp_pn] = signers_data.emplace_back();
|
||||
|
||||
if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &secp_pk, part_pk.data(), part_pk.size())) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!secp256k1_musig_pubnonce_parse(secp256k1_context_static, &secp_pn, pubnonce.data())) {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
if (our_pubkey_idx == std::nullopt) {
|
||||
return std::nullopt;
|
||||
}
|
||||
pubnonce_ptrs.reserve(signers_data.size());
|
||||
for (auto& [_, pn] : signers_data) {
|
||||
pubnonce_ptrs.push_back(&pn);
|
||||
}
|
||||
|
||||
// Aggregate nonces
|
||||
secp256k1_musig_aggnonce aggnonce;
|
||||
if (!secp256k1_musig_nonce_agg(secp256k1_context_static, &aggnonce, pubnonce_ptrs.data(), pubnonce_ptrs.size())) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Apply tweaks
|
||||
for (const auto& [tweak, xonly] : tweaks) {
|
||||
if (xonly) {
|
||||
if (!secp256k1_musig_pubkey_xonly_tweak_add(secp256k1_context_static, nullptr, &keyagg_cache, tweak.data())) {
|
||||
return std::nullopt;
|
||||
}
|
||||
} else if (!secp256k1_musig_pubkey_ec_tweak_add(secp256k1_context_static, nullptr, &keyagg_cache, tweak.data())) {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
// Create musig_session
|
||||
secp256k1_musig_session session;
|
||||
if (!secp256k1_musig_nonce_process(secp256k1_context_static, &session, &aggnonce, sighash.data(), &keyagg_cache)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Create partial signature
|
||||
secp256k1_musig_partial_sig psig;
|
||||
if (!secp256k1_musig_partial_sign(secp256k1_context_static, &psig, secnonce.Get(), &keypair, &keyagg_cache, &session)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
// The secnonce must be deleted after signing to prevent nonce reuse.
|
||||
secnonce.Invalidate();
|
||||
|
||||
// Verify partial signature
|
||||
if (!secp256k1_musig_partial_sig_verify(secp256k1_context_static, &psig, &(signers_data.at(*our_pubkey_idx).second), &(signers_data.at(*our_pubkey_idx).first), &keyagg_cache, &session)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Serialize
|
||||
uint256 sig;
|
||||
if (!secp256k1_musig_partial_sig_serialize(secp256k1_context_static, sig.data(), &psig)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
CKey GenerateRandomKey(bool compressed) noexcept
|
||||
{
|
||||
CKey key;
|
||||
|
||||
@ -223,6 +223,7 @@ public:
|
||||
KeyPair ComputeKeyPair(const uint256* merkle_root) const;
|
||||
|
||||
std::vector<uint8_t> CreateMuSig2Nonce(MuSig2SecNonce& secnonce, const uint256& sighash, const CPubKey& aggregate_pubkey, const std::vector<CPubKey>& pubkeys);
|
||||
std::optional<uint256> CreateMuSig2PartialSig(const uint256& hash, const CPubKey& aggregate_pubkey, const std::vector<CPubKey>& pubkeys, const std::map<CPubKey, std::vector<uint8_t>>& pubnonces, MuSig2SecNonce& secnonce, const std::vector<std::pair<uint256, bool>>& tweaks);
|
||||
};
|
||||
|
||||
CKey GenerateRandomKey(bool compressed = true) noexcept;
|
||||
|
||||
@ -130,6 +130,50 @@ std::vector<uint8_t> MutableTransactionSignatureCreator::CreateMuSig2Nonce(const
|
||||
return out;
|
||||
}
|
||||
|
||||
bool MutableTransactionSignatureCreator::CreateMuSig2PartialSig(const SigningProvider& provider, uint256& partial_sig, const CPubKey& aggregate_pubkey, const CPubKey& script_pubkey, const CPubKey& part_pubkey, const uint256* leaf_hash, const std::vector<std::pair<uint256, bool>>& tweaks, SigVersion sigversion, const SignatureData& sigdata) const
|
||||
{
|
||||
assert(sigversion == SigVersion::TAPROOT || sigversion == SigVersion::TAPSCRIPT);
|
||||
|
||||
// Retrieve private key
|
||||
CKey key;
|
||||
if (!provider.GetKey(part_pubkey.GetID(), key)) return false;
|
||||
|
||||
// Retrieve participant pubkeys
|
||||
auto it = sigdata.musig2_pubkeys.find(aggregate_pubkey);
|
||||
if (it == sigdata.musig2_pubkeys.end()) return false;
|
||||
const std::vector<CPubKey>& pubkeys = it->second;
|
||||
if (std::find(pubkeys.begin(), pubkeys.end(), part_pubkey) == pubkeys.end()) return {};
|
||||
|
||||
// Retrieve pubnonces
|
||||
auto this_leaf_aggkey = std::make_pair(script_pubkey, leaf_hash ? *leaf_hash : uint256());
|
||||
auto pubnonce_it = sigdata.musig2_pubnonces.find(this_leaf_aggkey);
|
||||
if (pubnonce_it == sigdata.musig2_pubnonces.end()) return false;
|
||||
const std::map<CPubKey, std::vector<uint8_t>>& pubnonces = pubnonce_it->second;
|
||||
|
||||
// Check if enough pubnonces
|
||||
if (pubnonces.size() != pubkeys.size()) return false;
|
||||
|
||||
// Compute sighash
|
||||
std::optional<uint256> sighash = ComputeSchnorrSignatureHash(leaf_hash, sigversion);
|
||||
if (!sighash.has_value()) return false;
|
||||
|
||||
// Retrieve the secnonce
|
||||
uint256 session_id = MuSig2SessionID(script_pubkey, part_pubkey, *sighash);
|
||||
std::optional<std::reference_wrapper<MuSig2SecNonce>> secnonce = provider.GetMuSig2SecNonce(session_id);
|
||||
if (!secnonce || !secnonce->get().IsValid()) return false;
|
||||
|
||||
// Compute the sig
|
||||
std::optional<uint256> sig = key.CreateMuSig2PartialSig(*sighash, aggregate_pubkey, pubkeys, pubnonces, *secnonce, tweaks);
|
||||
if (!sig) return false;
|
||||
partial_sig = std::move(*sig);
|
||||
|
||||
// Delete the secnonce now that we're done with it
|
||||
assert(!secnonce->get().IsValid());
|
||||
provider.DeleteMuSig2Session(session_id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool GetCScript(const SigningProvider& provider, const SignatureData& sigdata, const CScriptID& scriptid, CScript& script)
|
||||
{
|
||||
if (provider.GetCScript(scriptid, script)) {
|
||||
@ -791,6 +835,11 @@ public:
|
||||
out.assign(MUSIG2_PUBNONCE_SIZE, '\000');
|
||||
return out;
|
||||
}
|
||||
bool CreateMuSig2PartialSig(const SigningProvider& provider, uint256& partial_sig, const CPubKey& aggregate_pubkey, const CPubKey& script_pubkey, const CPubKey& part_pubkey, const uint256* leaf_hash, const std::vector<std::pair<uint256, bool>>& tweaks, SigVersion sigversion, const SignatureData& sigdata) const override
|
||||
{
|
||||
partial_sig = uint256::ONE;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -35,6 +35,7 @@ public:
|
||||
virtual bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const =0;
|
||||
virtual bool CreateSchnorrSig(const SigningProvider& provider, std::vector<unsigned char>& sig, const XOnlyPubKey& pubkey, const uint256* leaf_hash, const uint256* merkle_root, SigVersion sigversion) const =0;
|
||||
virtual std::vector<uint8_t> CreateMuSig2Nonce(const SigningProvider& provider, const CPubKey& aggregate_pubkey, const CPubKey& script_pubkey, const CPubKey& part_pubkey, const uint256* leaf_hash, const uint256* merkle_root, SigVersion sigversion, const SignatureData& sigdata) const =0;
|
||||
virtual bool CreateMuSig2PartialSig(const SigningProvider& provider, uint256& partial_sig, const CPubKey& aggregate_pubkey, const CPubKey& script_pubkey, const CPubKey& part_pubkey, const uint256* leaf_hash, const std::vector<std::pair<uint256, bool>>& tweaks, SigVersion sigversion, const SignatureData& sigdata) const =0;
|
||||
};
|
||||
|
||||
/** A signature creator for transactions. */
|
||||
@ -56,6 +57,7 @@ public:
|
||||
bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override;
|
||||
bool CreateSchnorrSig(const SigningProvider& provider, std::vector<unsigned char>& sig, const XOnlyPubKey& pubkey, const uint256* leaf_hash, const uint256* merkle_root, SigVersion sigversion) const override;
|
||||
std::vector<uint8_t> CreateMuSig2Nonce(const SigningProvider& provider, const CPubKey& aggregate_pubkey, const CPubKey& script_pubkey, const CPubKey& part_pubkey, const uint256* leaf_hash, const uint256* merkle_root, SigVersion sigversion, const SignatureData& sigdata) const override;
|
||||
bool CreateMuSig2PartialSig(const SigningProvider& provider, uint256& partial_sig, const CPubKey& aggregate_pubkey, const CPubKey& script_pubkey, const CPubKey& part_pubkey, const uint256* leaf_hash, const std::vector<std::pair<uint256, bool>>& tweaks, SigVersion sigversion, const SignatureData& sigdata) const override;
|
||||
};
|
||||
|
||||
/** A signature checker that accepts all signatures */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user