UltrafastSecp256k1 3.50.0
Ultra high-performance secp256k1 elliptic curve cryptography library
Loading...
Searching...
No Matches
musig2.hpp
Go to the documentation of this file.
1#ifndef SECP256K1_MUSIG2_HPP
2#define SECP256K1_MUSIG2_HPP
3#pragma once
4
5// ============================================================================
6// MuSig2: Two-Round Multi-Signature Scheme for secp256k1
7// ============================================================================
8// Implements MuSig2 (BIP-327) -- a Schnorr-based multi-signature protocol
9// where N signers produce a single signature verifiable against an
10// aggregated public key.
11//
12// Protocol:
13// 1. Key Aggregation: Q = KeyAgg(pk_1, ..., pk_n)
14// 2. Nonce Generation: Each signer generates nonce pair (R_1, R_2)
15// 3. Nonce Aggregation: Combine all nonces via deterministic coefficient
16// 4. Partial Signing: Each signer produces partial signature s_i
17// 5. Signature Aggregation: s = sum(s_i), final sig = (R, s)
18//
19// The final signature is a standard BIP-340 Schnorr signature.
20//
21// Reference: https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki
22// ============================================================================
23
24#include <array>
25#include <cstddef>
26#include <cstdint>
27#include <vector>
28#include "secp256k1/scalar.hpp"
29#include "secp256k1/point.hpp"
30
31namespace secp256k1 {
32
33// -- Key Aggregation Context --------------------------------------------------
34
36 fast::Point Q; // Aggregated public key
37 std::array<std::uint8_t, 32> Q_x; // X-only aggregated pubkey
38 std::vector<fast::Scalar> key_coefficients; // a_i for each signer
39 bool Q_negated; // Whether Q was negated for even-Y
40};
41
42// Aggregate public keys (KeyAgg from BIP-327).
43// pubkeys: array of X-only public keys (32 bytes each)
44// Returns aggregation context with combined key and coefficients.
45// If ANY pubkey is invalid (x >= p or not on curve), returns ctx with Q = infinity.
46MuSig2KeyAggCtx musig2_key_agg(const std::vector<std::array<std::uint8_t, 32>>& pubkeys);
47
48// -- Nonce --------------------------------------------------------------------
49
51 fast::Scalar k1; // First secret nonce
52 fast::Scalar k2; // Second secret nonce
53};
54
56 std::array<std::uint8_t, 33> R1; // First public nonce (compressed)
57 std::array<std::uint8_t, 33> R2; // Second public nonce (compressed)
58
59 // Serialize to 66 bytes
60 std::array<std::uint8_t, 66> serialize() const;
61 static MuSig2PubNonce deserialize(const std::array<std::uint8_t, 66>& data);
62};
63
64// Generate a nonce pair deterministically.
65// secret_key: signer's private key
66// pub_key: signer's public key (X-only)
67// agg_pub_key: aggregated public key (X-only)
68// msg: 32-byte message
69// extra_input: optional extra randomness (32 bytes, or nullptr)
70//
71// Returns {secret_nonce, public_nonce}
72std::pair<MuSig2SecNonce, MuSig2PubNonce> musig2_nonce_gen(
73 const fast::Scalar& secret_key,
74 const std::array<std::uint8_t, 32>& pub_key,
75 const std::array<std::uint8_t, 32>& agg_pub_key,
76 const std::array<std::uint8_t, 32>& msg,
77 const std::uint8_t* extra_input = nullptr);
78
79// -- Nonce Aggregation --------------------------------------------------------
80
82 fast::Point R1; // Aggregated first nonce point
83 fast::Point R2; // Aggregated second nonce point
84};
85
86// Aggregate all signers' public nonces.
87MuSig2AggNonce musig2_nonce_agg(const std::vector<MuSig2PubNonce>& pub_nonces);
88
89// -- Session (Signing) --------------------------------------------------------
90
92 fast::Point R; // Final nonce point
93 fast::Scalar b; // Nonce coefficient
94 fast::Scalar e; // Challenge
95 bool R_negated; // Whether R was negated
96};
97
98// Start a signing session: compute the effective R, b, and challenge e.
100 const MuSig2AggNonce& agg_nonce,
101 const MuSig2KeyAggCtx& key_agg_ctx,
102 const std::array<std::uint8_t, 32>& msg);
103
104// -- Partial Signing ----------------------------------------------------------
105
106// Produce a partial signature.
107// s_i = k1 + b*k2 + e * a_i * d_i (mod n)
108// where d_i is adjusted for Q/R negation.
109// sec_nonce is CONSUMED — both k1 and k2 are zeroized before return
110// to enforce single-use (M-03 nonce-reuse prevention).
112 MuSig2SecNonce& sec_nonce,
113 const fast::Scalar& secret_key,
114 const MuSig2KeyAggCtx& key_agg_ctx,
115 const MuSig2Session& session,
116 std::size_t signer_index);
117
118// Verify a partial signature (optional, for honest-signer detection).
120 const fast::Scalar& partial_sig,
121 const MuSig2PubNonce& pub_nonce,
122 const std::array<std::uint8_t, 32>& pubkey,
123 const MuSig2KeyAggCtx& key_agg_ctx,
124 const MuSig2Session& session,
125 std::size_t signer_index);
126
127// -- Signature Aggregation ----------------------------------------------------
128
129// Aggregate partial signatures into a final BIP-340 Schnorr signature.
130// Returns {r (32 bytes), s (32 bytes)} = standard 64-byte Schnorr sig.
131std::array<std::uint8_t, 64> musig2_partial_sig_agg(
132 const std::vector<fast::Scalar>& partial_sigs,
133 const MuSig2Session& session);
134
135} // namespace secp256k1
136
137#endif // SECP256K1_MUSIG2_HPP
MuSig2KeyAggCtx musig2_key_agg(const std::vector< std::array< std::uint8_t, 32 > > &pubkeys)
MuSig2AggNonce musig2_nonce_agg(const std::vector< MuSig2PubNonce > &pub_nonces)
fast::Scalar musig2_partial_sign(MuSig2SecNonce &sec_nonce, const fast::Scalar &secret_key, const MuSig2KeyAggCtx &key_agg_ctx, const MuSig2Session &session, std::size_t signer_index)
MuSig2Session musig2_start_sign_session(const MuSig2AggNonce &agg_nonce, const MuSig2KeyAggCtx &key_agg_ctx, const std::array< std::uint8_t, 32 > &msg)
bool musig2_partial_verify(const fast::Scalar &partial_sig, const MuSig2PubNonce &pub_nonce, const std::array< std::uint8_t, 32 > &pubkey, const MuSig2KeyAggCtx &key_agg_ctx, const MuSig2Session &session, std::size_t signer_index)
std::pair< MuSig2SecNonce, MuSig2PubNonce > musig2_nonce_gen(const fast::Scalar &secret_key, const std::array< std::uint8_t, 32 > &pub_key, const std::array< std::uint8_t, 32 > &agg_pub_key, const std::array< std::uint8_t, 32 > &msg, const std::uint8_t *extra_input=nullptr)
std::array< std::uint8_t, 64 > musig2_partial_sig_agg(const std::vector< fast::Scalar > &partial_sigs, const MuSig2Session &session)
std::vector< fast::Scalar > key_coefficients
Definition musig2.hpp:38
std::array< std::uint8_t, 32 > Q_x
Definition musig2.hpp:37
std::array< std::uint8_t, 33 > R2
Definition musig2.hpp:57
std::array< std::uint8_t, 33 > R1
Definition musig2.hpp:56
static MuSig2PubNonce deserialize(const std::array< std::uint8_t, 66 > &data)
std::array< std::uint8_t, 66 > serialize() const