Skip to content

Commit bf69442

Browse files
committed
sign: Add CreateMuSig2PartialSig
1 parent 512b17f commit bf69442

File tree

4 files changed

+141
-0
lines changed

4 files changed

+141
-0
lines changed

src/key.cpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,95 @@ std::vector<uint8_t> CKey::CreateMuSig2Nonce(MuSig2SecNonce& secnonce, const uin
383383
return out;
384384
}
385385

386+
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)
387+
{
388+
secp256k1_keypair keypair;
389+
if (!secp256k1_keypair_create(secp256k1_context_sign, &keypair, UCharCast(begin()))) return std::nullopt;
390+
391+
// Get the keyagg cache and aggregate pubkey
392+
secp256k1_musig_keyagg_cache keyagg_cache;
393+
if (!MuSig2AggregatePubkeys(pubkeys, keyagg_cache, aggregate_pubkey)) return std::nullopt;
394+
395+
// Check that there are enough pubnonces
396+
if (pubnonces.size() != pubkeys.size()) return std::nullopt;
397+
398+
// Parse the pubnonces
399+
std::vector<std::pair<secp256k1_pubkey, secp256k1_musig_pubnonce>> signers_data;
400+
std::vector<const secp256k1_musig_pubnonce*> pubnonce_ptrs;
401+
std::optional<size_t> our_pubkey_idx;
402+
CPubKey our_pubkey = GetPubKey();
403+
for (const CPubKey& part_pk : pubkeys) {
404+
const auto& pn_it = pubnonces.find(part_pk);
405+
if (pn_it == pubnonces.end()) return std::nullopt;
406+
const std::vector<uint8_t> pubnonce = pn_it->second;
407+
if (pubnonce.size() != MUSIG2_PUBNONCE_SIZE) return std::nullopt;
408+
if (part_pk == our_pubkey) {
409+
our_pubkey_idx = signers_data.size();
410+
}
411+
412+
auto& [secp_pk, secp_pn] = signers_data.emplace_back();
413+
414+
if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &secp_pk, part_pk.data(), part_pk.size())) {
415+
return std::nullopt;
416+
}
417+
418+
if (!secp256k1_musig_pubnonce_parse(secp256k1_context_static, &secp_pn, pubnonce.data())) {
419+
return std::nullopt;
420+
}
421+
}
422+
if (our_pubkey_idx == std::nullopt) {
423+
return std::nullopt;
424+
}
425+
pubnonce_ptrs.reserve(signers_data.size());
426+
for (auto& [_, pn] : signers_data) {
427+
pubnonce_ptrs.push_back(&pn);
428+
}
429+
430+
// Aggregate nonces
431+
secp256k1_musig_aggnonce aggnonce;
432+
if (!secp256k1_musig_nonce_agg(secp256k1_context_static, &aggnonce, pubnonce_ptrs.data(), pubnonce_ptrs.size())) {
433+
return std::nullopt;
434+
}
435+
436+
// Apply tweaks
437+
for (const auto& [tweak, xonly] : tweaks) {
438+
if (xonly) {
439+
if (!secp256k1_musig_pubkey_xonly_tweak_add(secp256k1_context_static, nullptr, &keyagg_cache, tweak.data())) {
440+
return std::nullopt;
441+
}
442+
} else if (!secp256k1_musig_pubkey_ec_tweak_add(secp256k1_context_static, nullptr, &keyagg_cache, tweak.data())) {
443+
return std::nullopt;
444+
}
445+
}
446+
447+
// Create musig_session
448+
secp256k1_musig_session session;
449+
if (!secp256k1_musig_nonce_process(secp256k1_context_static, &session, &aggnonce, sighash.data(), &keyagg_cache)) {
450+
return std::nullopt;
451+
}
452+
453+
// Create partial signature
454+
secp256k1_musig_partial_sig psig;
455+
if (!secp256k1_musig_partial_sign(secp256k1_context_static, &psig, secnonce.Get(), &keypair, &keyagg_cache, &session)) {
456+
return std::nullopt;
457+
}
458+
// The secnonce must be deleted after signing to prevent nonce reuse.
459+
secnonce.Invalidate();
460+
461+
// Verify partial signature
462+
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)) {
463+
return std::nullopt;
464+
}
465+
466+
// Serialize
467+
uint256 sig;
468+
if (!secp256k1_musig_partial_sig_serialize(secp256k1_context_static, sig.data(), &psig)) {
469+
return std::nullopt;
470+
}
471+
472+
return sig;
473+
}
474+
386475
CKey GenerateRandomKey(bool compressed) noexcept
387476
{
388477
CKey key;

src/key.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ class CKey
223223
KeyPair ComputeKeyPair(const uint256* merkle_root) const;
224224

225225
std::vector<uint8_t> CreateMuSig2Nonce(MuSig2SecNonce& secnonce, const uint256& sighash, const CPubKey& aggregate_pubkey, const std::vector<CPubKey>& pubkeys);
226+
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);
226227
};
227228

228229
CKey GenerateRandomKey(bool compressed = true) noexcept;

src/script/sign.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,50 @@ std::vector<uint8_t> MutableTransactionSignatureCreator::CreateMuSig2Nonce(const
130130
return out;
131131
}
132132

133+
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
134+
{
135+
assert(sigversion == SigVersion::TAPROOT || sigversion == SigVersion::TAPSCRIPT);
136+
137+
// Retrieve private key
138+
CKey key;
139+
if (!provider.GetKey(part_pubkey.GetID(), key)) return false;
140+
141+
// Retrieve participant pubkeys
142+
auto it = sigdata.musig2_pubkeys.find(aggregate_pubkey);
143+
if (it == sigdata.musig2_pubkeys.end()) return false;
144+
const std::vector<CPubKey>& pubkeys = it->second;
145+
if (std::find(pubkeys.begin(), pubkeys.end(), part_pubkey) == pubkeys.end()) return {};
146+
147+
// Retrieve pubnonces
148+
auto this_leaf_aggkey = std::make_pair(script_pubkey, leaf_hash ? *leaf_hash : uint256());
149+
auto pubnonce_it = sigdata.musig2_pubnonces.find(this_leaf_aggkey);
150+
if (pubnonce_it == sigdata.musig2_pubnonces.end()) return false;
151+
const std::map<CPubKey, std::vector<uint8_t>>& pubnonces = pubnonce_it->second;
152+
153+
// Check if enough pubnonces
154+
if (pubnonces.size() != pubkeys.size()) return false;
155+
156+
// Compute sighash
157+
std::optional<uint256> sighash = ComputeSchnorrSignatureHash(leaf_hash, sigversion);
158+
if (!sighash.has_value()) return false;
159+
160+
// Retrieve the secnonce
161+
uint256 session_id = MuSig2SessionID(script_pubkey, part_pubkey, *sighash);
162+
std::optional<std::reference_wrapper<MuSig2SecNonce>> secnonce = provider.GetMuSig2SecNonce(session_id);
163+
if (!secnonce || !secnonce->get().IsValid()) return false;
164+
165+
// Compute the sig
166+
std::optional<uint256> sig = key.CreateMuSig2PartialSig(*sighash, aggregate_pubkey, pubkeys, pubnonces, *secnonce, tweaks);
167+
if (!sig) return false;
168+
partial_sig = std::move(*sig);
169+
170+
// Delete the secnonce now that we're done with it
171+
assert(!secnonce->get().IsValid());
172+
provider.DeleteMuSig2Session(session_id);
173+
174+
return true;
175+
}
176+
133177
static bool GetCScript(const SigningProvider& provider, const SignatureData& sigdata, const CScriptID& scriptid, CScript& script)
134178
{
135179
if (provider.GetCScript(scriptid, script)) {
@@ -791,6 +835,11 @@ class DummySignatureCreator final : public BaseSignatureCreator {
791835
out.assign(MUSIG2_PUBNONCE_SIZE, '\000');
792836
return out;
793837
}
838+
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
839+
{
840+
partial_sig = uint256::ONE;
841+
return true;
842+
}
794843
};
795844

796845
}

src/script/sign.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class BaseSignatureCreator {
3535
virtual bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const =0;
3636
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;
3737
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;
38+
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;
3839
};
3940

4041
/** A signature creator for transactions. */
@@ -56,6 +57,7 @@ class MutableTransactionSignatureCreator : public BaseSignatureCreator
5657
bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override;
5758
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;
5859
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;
60+
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;
5961
};
6062

6163
/** A signature checker that accepts all signatures */

0 commit comments

Comments
 (0)