Skip to content

Commit 512b17f

Browse files
committed
sign: Add CreateMuSig2Nonce
1 parent 82ea67c commit 512b17f

File tree

7 files changed

+88
-1
lines changed

7 files changed

+88
-1
lines changed

src/key.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <secp256k1.h>
1414
#include <secp256k1_ellswift.h>
1515
#include <secp256k1_extrakeys.h>
16+
#include <secp256k1_musig.h>
1617
#include <secp256k1_recovery.h>
1718
#include <secp256k1_schnorrsig.h>
1819

@@ -349,6 +350,39 @@ KeyPair CKey::ComputeKeyPair(const uint256* merkle_root) const
349350
return KeyPair(*this, merkle_root);
350351
}
351352

353+
std::vector<uint8_t> CKey::CreateMuSig2Nonce(MuSig2SecNonce& secnonce, const uint256& sighash, const CPubKey& aggregate_pubkey, const std::vector<CPubKey>& pubkeys)
354+
{
355+
// Get the keyagg cache and aggregate pubkey
356+
secp256k1_musig_keyagg_cache keyagg_cache;
357+
if (!MuSig2AggregatePubkeys(pubkeys, keyagg_cache, aggregate_pubkey)) return {};
358+
359+
// Parse participant pubkey
360+
CPubKey our_pubkey = GetPubKey();
361+
secp256k1_pubkey pubkey;
362+
if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, our_pubkey.data(), our_pubkey.size())) {
363+
return {};
364+
}
365+
366+
// Generate randomness for nonce
367+
uint256 rand;
368+
GetStrongRandBytes(rand);
369+
370+
// Generate nonce
371+
secp256k1_musig_pubnonce pubnonce;
372+
if (!secp256k1_musig_nonce_gen(secp256k1_context_sign, secnonce.Get(), &pubnonce, rand.data(), UCharCast(begin()), &pubkey, sighash.data(), &keyagg_cache, nullptr)) {
373+
return {};
374+
}
375+
376+
// Serialize pubnonce
377+
std::vector<uint8_t> out;
378+
out.resize(MUSIG2_PUBNONCE_SIZE);
379+
if (!secp256k1_musig_pubnonce_serialize(secp256k1_context_static, out.data(), &pubnonce)) {
380+
return {};
381+
}
382+
383+
return out;
384+
}
385+
352386
CKey GenerateRandomKey(bool compressed) noexcept
353387
{
354388
CKey key;

src/key.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#ifndef BITCOIN_KEY_H
88
#define BITCOIN_KEY_H
99

10+
#include <musig.h>
1011
#include <pubkey.h>
1112
#include <serialize.h>
1213
#include <support/allocators/secure.h>
@@ -220,6 +221,8 @@ class CKey
220221
* Merkle root of the script tree).
221222
*/
222223
KeyPair ComputeKeyPair(const uint256* merkle_root) const;
224+
225+
std::vector<uint8_t> CreateMuSig2Nonce(MuSig2SecNonce& secnonce, const uint256& sighash, const CPubKey& aggregate_pubkey, const std::vector<CPubKey>& pubkeys);
223226
};
224227

225228
CKey GenerateRandomKey(bool compressed = true) noexcept;

src/musig.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,10 @@ bool MuSig2SecNonce::IsValid()
111111
{
112112
return m_impl->IsValid();
113113
}
114+
115+
uint256 MuSig2SessionID(const CPubKey& script_pubkey, const CPubKey& part_pubkey, const uint256& sighash)
116+
{
117+
HashWriter hasher;
118+
hasher << script_pubkey << part_pubkey << sighash;
119+
return hasher.GetSHA256();
120+
}

src/musig.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ struct secp256k1_musig_secnonce;
1818
using namespace util::hex_literals;
1919
constexpr uint256 MUSIG_CHAINCODE{"868087ca02a6f974c4598924c36b57762d32cb45717167e300622c7167e38965"_hex_u8};
2020

21+
constexpr size_t MUSIG2_PUBNONCE_SIZE{66};
22+
2123
//! Compute the full aggregate pubkey from the given participant pubkeys in their current order.
2224
//! Outputs the secp256k1_musig_keyagg_cache and validates that the computed aggregate pubkey matches an expected aggregate pubkey.
2325
//! This is necessary for most MuSig2 operations.
@@ -58,4 +60,6 @@ class MuSig2SecNonce
5860
bool IsValid();
5961
};
6062

63+
uint256 MuSig2SessionID(const CPubKey& script_pubkey, const CPubKey& part_pubkey, const uint256& sighash);
64+
6165
#endif // BITCOIN_MUSIG_H

src/psbt.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,7 @@ struct PSBTInput
794794

795795
std::vector<uint8_t> pubnonce;
796796
s >> pubnonce;
797-
if (pubnonce.size() != 66) {
797+
if (pubnonce.size() != MUSIG2_PUBNONCE_SIZE) {
798798
throw std::ios_base::failure("Input musig2 pubnonce value is not 66 bytes");
799799
}
800800

src/script/sign.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77

88
#include <consensus/amount.h>
99
#include <key.h>
10+
#include <musig.h>
1011
#include <policy/policy.h>
1112
#include <primitives/transaction.h>
13+
#include <random.h>
1214
#include <script/keyorigin.h>
1315
#include <script/miniscript.h>
1416
#include <script/script.h>
@@ -100,6 +102,34 @@ bool MutableTransactionSignatureCreator::CreateSchnorrSig(const SigningProvider&
100102
return true;
101103
}
102104

105+
std::vector<uint8_t> MutableTransactionSignatureCreator::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
106+
{
107+
assert(sigversion == SigVersion::TAPROOT || sigversion == SigVersion::TAPSCRIPT);
108+
109+
// Retrieve the private key
110+
CKey key;
111+
if (!provider.GetKey(part_pubkey.GetID(), key)) return {};
112+
113+
// Retrieve participant pubkeys
114+
auto it = sigdata.musig2_pubkeys.find(aggregate_pubkey);
115+
if (it == sigdata.musig2_pubkeys.end()) return {};
116+
const std::vector<CPubKey>& pubkeys = it->second;
117+
if (std::find(pubkeys.begin(), pubkeys.end(), part_pubkey) == pubkeys.end()) return {};
118+
119+
// Compute sighash
120+
std::optional<uint256> sighash = ComputeSchnorrSignatureHash(leaf_hash, sigversion);
121+
if (!sighash.has_value()) return {};
122+
123+
MuSig2SecNonce secnonce;
124+
std::vector<uint8_t> out = key.CreateMuSig2Nonce(secnonce, *sighash, aggregate_pubkey, pubkeys);
125+
if (out.empty()) return {};
126+
127+
// Store the secnonce in the SigningProvider
128+
provider.SetMuSig2SecNonce(MuSig2SessionID(script_pubkey, part_pubkey, *sighash), std::move(secnonce));
129+
130+
return out;
131+
}
132+
103133
static bool GetCScript(const SigningProvider& provider, const SignatureData& sigdata, const CScriptID& scriptid, CScript& script)
104134
{
105135
if (provider.GetCScript(scriptid, script)) {
@@ -755,6 +785,12 @@ class DummySignatureCreator final : public BaseSignatureCreator {
755785
sig.assign(64, '\000');
756786
return true;
757787
}
788+
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
789+
{
790+
std::vector<uint8_t> out;
791+
out.assign(MUSIG2_PUBNONCE_SIZE, '\000');
792+
return out;
793+
}
758794
};
759795

760796
}

src/script/sign.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class SigningProvider;
2323

2424
struct bilingual_str;
2525
struct CMutableTransaction;
26+
struct SignatureData;
2627

2728
/** Interface for signature creators. */
2829
class BaseSignatureCreator {
@@ -33,6 +34,7 @@ class BaseSignatureCreator {
3334
/** Create a singular (non-script) signature. */
3435
virtual bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const =0;
3536
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;
37+
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;
3638
};
3739

3840
/** A signature creator for transactions. */
@@ -53,6 +55,7 @@ class MutableTransactionSignatureCreator : public BaseSignatureCreator
5355
const BaseSignatureChecker& Checker() const override { return checker; }
5456
bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override;
5557
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;
58+
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;
5659
};
5760

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

0 commit comments

Comments
 (0)