Skip to content

Commit 3e8e6d9

Browse files
committed
Add BIP-373 PSBT_{IN,OUT}_MUSIG2_PARTICIPANT_PUBKEYS serialization and deserialization
1 parent ecf4b2b commit 3e8e6d9

File tree

3 files changed

+51
-0
lines changed

3 files changed

+51
-0
lines changed

bitcoin/src/psbt/map/input.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ const PSBT_IN_TAP_BIP32_DERIVATION: u64 = 0x16;
5959
const PSBT_IN_TAP_INTERNAL_KEY: u64 = 0x17;
6060
/// Type: Taproot Merkle Root PSBT_IN_TAP_MERKLE_ROOT = 0x18
6161
const PSBT_IN_TAP_MERKLE_ROOT: u64 = 0x18;
62+
/// Type: MuSig2 Public Keys Participating in Aggregate Input PSBT_IN_MUSIG2_PARTICIPANT_PUBKEYS = 0x1a
63+
const PSBT_IN_MUSIG2_PARTICIPANT_PUBKEYS: u64 = 0x1a;
6264
/// Type: Proprietary Use Type PSBT_IN_PROPRIETARY = 0xFC
6365
const PSBT_IN_PROPRIETARY: u64 = 0xFC;
6466

@@ -113,6 +115,8 @@ pub struct Input {
113115
pub tap_internal_key: Option<XOnlyPublicKey>,
114116
/// Taproot Merkle root.
115117
pub tap_merkle_root: Option<TapNodeHash>,
118+
/// Mapping from MuSig2 aggregate keys to the participant keys from which they were aggregated.
119+
pub musig2_participant_pubkeys: BTreeMap<secp256k1::PublicKey, Vec<secp256k1::PublicKey>>,
116120
/// Proprietary key-value pairs for this input.
117121
pub proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>>,
118122
/// Unknown key-value pairs for this input.
@@ -352,6 +356,11 @@ impl Input {
352356
self.tap_merkle_root <= <raw_key: _>|< raw_value: TapNodeHash>
353357
}
354358
}
359+
PSBT_IN_MUSIG2_PARTICIPANT_PUBKEYS => {
360+
impl_psbt_insert_pair! {
361+
self.musig2_participant_pubkeys <= <raw_key: secp256k1::PublicKey>|< raw_value: Vec<secp256k1::PublicKey> >
362+
}
363+
}
355364
PSBT_IN_PROPRIETARY => {
356365
let key = raw::ProprietaryKey::try_from(raw_key.clone())?;
357366
match self.proprietary.entry(key) {
@@ -390,6 +399,7 @@ impl Input {
390399
self.tap_script_sigs.extend(other.tap_script_sigs);
391400
self.tap_scripts.extend(other.tap_scripts);
392401
self.tap_key_origins.extend(other.tap_key_origins);
402+
self.musig2_participant_pubkeys.extend(other.musig2_participant_pubkeys);
393403
self.proprietary.extend(other.proprietary);
394404
self.unknown.extend(other.unknown);
395405

@@ -482,6 +492,11 @@ impl Map for Input {
482492
impl_psbt_get_pair! {
483493
rv.push(self.tap_merkle_root, PSBT_IN_TAP_MERKLE_ROOT)
484494
}
495+
496+
impl_psbt_get_pair! {
497+
rv.push_map(self.musig2_participant_pubkeys, PSBT_IN_MUSIG2_PARTICIPANT_PUBKEYS)
498+
}
499+
485500
for (key, value) in self.proprietary.iter() {
486501
rv.push(raw::Pair { key: key.to_key(), value: value.clone() });
487502
}

bitcoin/src/psbt/map/output.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ const PSBT_OUT_TAP_INTERNAL_KEY: u64 = 0x05;
2020
const PSBT_OUT_TAP_TREE: u64 = 0x06;
2121
/// Type: Taproot Key BIP 32 Derivation Path PSBT_OUT_TAP_BIP32_DERIVATION = 0x07
2222
const PSBT_OUT_TAP_BIP32_DERIVATION: u64 = 0x07;
23+
/// Type: MuSig2 Public Keys Participating in Aggregate Output PSBT_OUT_MUSIG2_PARTICIPANT_PUBKEYS = 0x08
24+
const PSBT_OUT_MUSIG2_PARTICIPANT_PUBKEYS: u64 = 0x08;
2325
/// Type: Proprietary Use Type PSBT_IN_PROPRIETARY = 0xFC
2426
const PSBT_OUT_PROPRIETARY: u64 = 0xFC;
2527

@@ -40,6 +42,8 @@ pub struct Output {
4042
pub tap_tree: Option<TapTree>,
4143
/// Map of tap root x only keys to origin info and leaf hashes contained in it.
4244
pub tap_key_origins: BTreeMap<XOnlyPublicKey, (Vec<TapLeafHash>, KeySource)>,
45+
/// Mapping from MuSig2 aggregate keys to the participant keys from which they were aggregated.
46+
pub musig2_participant_pubkeys: BTreeMap<secp256k1::PublicKey, Vec<secp256k1::PublicKey>>,
4347
/// Proprietary key-value pairs for this output.
4448
pub proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>>,
4549
/// Unknown key-value pairs for this output.
@@ -90,6 +94,11 @@ impl Output {
9094
self.tap_key_origins <= <raw_key: XOnlyPublicKey>|< raw_value: (Vec<TapLeafHash>, KeySource)>
9195
}
9296
}
97+
PSBT_OUT_MUSIG2_PARTICIPANT_PUBKEYS => {
98+
impl_psbt_insert_pair! {
99+
self.musig2_participant_pubkeys <= <raw_key: secp256k1::PublicKey>|< raw_value: Vec<secp256k1::PublicKey> >
100+
}
101+
}
93102
_ => match self.unknown.entry(raw_key) {
94103
btree_map::Entry::Vacant(empty_key) => {
95104
empty_key.insert(raw_value);
@@ -107,6 +116,7 @@ impl Output {
107116
self.proprietary.extend(other.proprietary);
108117
self.unknown.extend(other.unknown);
109118
self.tap_key_origins.extend(other.tap_key_origins);
119+
self.musig2_participant_pubkeys.extend(other.musig2_participant_pubkeys);
110120

111121
combine!(redeem_script, self, other);
112122
combine!(witness_script, self, other);
@@ -143,6 +153,10 @@ impl Map for Output {
143153
rv.push_map(self.tap_key_origins, PSBT_OUT_TAP_BIP32_DERIVATION)
144154
}
145155

156+
impl_psbt_get_pair! {
157+
rv.push_map(self.musig2_participant_pubkeys, PSBT_OUT_MUSIG2_PARTICIPANT_PUBKEYS)
158+
}
159+
146160
for (key, value) in self.proprietary.iter() {
147161
rv.push(raw::Pair { key: key.to_key(), value: value.clone() });
148162
}

bitcoin/src/psbt/serialize.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,28 @@ impl Deserialize for secp256k1::PublicKey {
172172
}
173173
}
174174

175+
impl Serialize for Vec<secp256k1::PublicKey> {
176+
fn serialize(&self) -> Vec<u8> {
177+
let mut result: Vec<u8> = Vec::with_capacity(secp256k1::constants::PUBLIC_KEY_SIZE * self.len());
178+
179+
for pubkey in self.iter() {
180+
result.extend(Serialize::serialize(pubkey));
181+
}
182+
183+
result
184+
}
185+
}
186+
187+
impl Deserialize for Vec<secp256k1::PublicKey> {
188+
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
189+
bytes.chunks(secp256k1::constants::PUBLIC_KEY_SIZE)
190+
.map(|pubkey_bytes| {
191+
secp256k1::PublicKey::deserialize(pubkey_bytes)
192+
})
193+
.collect()
194+
}
195+
}
196+
175197
impl Serialize for ecdsa::Signature {
176198
fn serialize(&self) -> Vec<u8> { self.to_vec() }
177199
}

0 commit comments

Comments
 (0)