Skip to content

Commit c06a1dc

Browse files
committed
Add MuSig2SecNonce class for secure allocation of musig nonces
1 parent 9baff05 commit c06a1dc

File tree

2 files changed

+74
-0
lines changed

2 files changed

+74
-0
lines changed

src/musig.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
44

55
#include <musig.h>
6+
#include <support/allocators/secure.h>
67

78
#include <secp256k1_musig.h>
89

@@ -62,3 +63,43 @@ CExtPubKey CreateMuSig2SyntheticXpub(const CPubKey& pubkey)
6263
extpub.pubkey = pubkey;
6364
return extpub;
6465
}
66+
67+
class MuSig2SecNonceImpl
68+
{
69+
private:
70+
//! The actual secnonce itself
71+
secure_unique_ptr<secp256k1_musig_secnonce> m_nonce;
72+
73+
public:
74+
MuSig2SecNonceImpl() : m_nonce{make_secure_unique<secp256k1_musig_secnonce>()} {}
75+
76+
// Delete copy constructors
77+
MuSig2SecNonceImpl(const MuSig2SecNonceImpl&) = delete;
78+
MuSig2SecNonceImpl& operator=(const MuSig2SecNonceImpl&) = delete;
79+
80+
secp256k1_musig_secnonce* Get() const { return m_nonce.get(); }
81+
void Invalidate() { m_nonce.reset(); }
82+
bool IsValid() { return m_nonce != nullptr; }
83+
};
84+
85+
MuSig2SecNonce::MuSig2SecNonce() : m_impl{std::make_unique<MuSig2SecNonceImpl>()} {}
86+
87+
MuSig2SecNonce::MuSig2SecNonce(MuSig2SecNonce&&) noexcept = default;
88+
MuSig2SecNonce& MuSig2SecNonce::operator=(MuSig2SecNonce&&) noexcept = default;
89+
90+
MuSig2SecNonce::~MuSig2SecNonce() = default;
91+
92+
secp256k1_musig_secnonce* MuSig2SecNonce::Get() const
93+
{
94+
return m_impl->Get();
95+
}
96+
97+
void MuSig2SecNonce::Invalidate()
98+
{
99+
return m_impl->Invalidate();
100+
}
101+
102+
bool MuSig2SecNonce::IsValid()
103+
{
104+
return m_impl->IsValid();
105+
}

src/musig.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#include <vector>
1212

1313
struct secp256k1_musig_keyagg_cache;
14+
class MuSig2SecNonceImpl;
15+
struct secp256k1_musig_secnonce;
1416

1517
//! MuSig2 chaincode as defined by BIP 328
1618
using namespace util::hex_literals;
@@ -26,4 +28,35 @@ std::optional<CPubKey> MuSig2AggregatePubkeys(const std::vector<CPubKey>& pubkey
2628
//! Construct the BIP 328 synthetic xpub for a pubkey
2729
CExtPubKey CreateMuSig2SyntheticXpub(const CPubKey& pubkey);
2830

31+
/**
32+
* MuSig2SecNonce encapsulates a secret nonce in use in a MuSig2 signing session.
33+
* Since this nonce persists outside of libsecp256k1 signing code, we must handle
34+
* its construction and destruction ourselves.
35+
* The secret nonce must be kept a secret, otherwise the private key may be leaked.
36+
* As such, it needs to be treated in the same way that CKeys are treated.
37+
* So this class handles the secure allocation of the secp256k1_musig_secnonce object
38+
* that libsecp256k1 uses, and only gives out references to this object to avoid
39+
* any possibility of copies being made. Furthermore, objects of this class are not
40+
* copyable to avoid nonce reuse.
41+
*/
42+
class MuSig2SecNonce
43+
{
44+
private:
45+
std::unique_ptr<MuSig2SecNonceImpl> m_impl;
46+
47+
public:
48+
MuSig2SecNonce();
49+
MuSig2SecNonce(MuSig2SecNonce&&) noexcept;
50+
MuSig2SecNonce& operator=(MuSig2SecNonce&&) noexcept;
51+
~MuSig2SecNonce();
52+
53+
// Delete copy constructors
54+
MuSig2SecNonce(const MuSig2SecNonce&) = delete;
55+
MuSig2SecNonce& operator=(const MuSig2SecNonce&) = delete;
56+
57+
secp256k1_musig_secnonce* Get() const;
58+
void Invalidate();
59+
bool IsValid();
60+
};
61+
2962
#endif // BITCOIN_MUSIG_H

0 commit comments

Comments
 (0)