Skip to content

Commit b20e250

Browse files
committed
Add serialization and deserialization for relevant MuSig2 types
Add serialization and deserialization for `secp256k1::musig::PublicNonce`, `secp256k1::musig::AggregatedNonce`, and `secp256k1::musig::PartialSignature`.
1 parent 7471b3c commit b20e250

File tree

1 file changed

+169
-1
lines changed

1 file changed

+169
-1
lines changed

src/musig.rs

Lines changed: 169 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use std;
1313

1414
use crate::ffi::{self, CPtr};
1515
use crate::{
16-
schnorr, Error, Keypair, Message, PublicKey, Scalar, Secp256k1, SecretKey, Signing,
16+
from_hex, schnorr, Error, Keypair, Message, PublicKey, Scalar, Secp256k1, SecretKey, Signing,
1717
Verification, XOnlyPublicKey,
1818
};
1919

@@ -209,6 +209,62 @@ impl CPtr for PartialSignature {
209209
fn as_mut_c_ptr(&mut self) -> *mut Self::Target { self.as_mut_ptr() }
210210
}
211211

212+
impl fmt::LowerHex for PartialSignature {
213+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
214+
for b in self.serialize() {
215+
write!(f, "{:02x}", b)?;
216+
}
217+
Ok(())
218+
}
219+
}
220+
221+
impl fmt::Display for PartialSignature {
222+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
223+
}
224+
225+
impl core::str::FromStr for PartialSignature {
226+
type Err = ParseError;
227+
fn from_str(s: &str) -> Result<Self, Self::Err> {
228+
let mut res = [0u8; ffi::MUSIG_PART_SIG_SERIALIZED_LEN];
229+
match from_hex(s, &mut res) {
230+
Ok(ffi::MUSIG_PART_SIG_SERIALIZED_LEN) => PartialSignature::from_byte_array(&res),
231+
_ => Err(ParseError::MalformedArg),
232+
}
233+
}
234+
}
235+
236+
#[cfg(feature = "serde")]
237+
impl serde::Serialize for PartialSignature {
238+
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
239+
if s.is_human_readable() {
240+
s.collect_str(self)
241+
} else {
242+
s.serialize_bytes(&self.serialize()[..])
243+
}
244+
}
245+
}
246+
247+
#[cfg(feature = "serde")]
248+
impl<'de> serde::Deserialize<'de> for PartialSignature {
249+
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
250+
if d.is_human_readable() {
251+
d.deserialize_str(super::serde_util::FromStrVisitor::new(
252+
"a hex string representing a MuSig2 partial signature",
253+
))
254+
} else {
255+
d.deserialize_bytes(super::serde_util::BytesVisitor::new(
256+
"a raw MuSig2 partial signature",
257+
|slice| {
258+
let bytes: &[u8; ffi::MUSIG_PART_SIG_SERIALIZED_LEN] =
259+
slice.try_into().map_err(|_| ParseError::MalformedArg)?;
260+
261+
Self::from_byte_array(bytes)
262+
},
263+
))
264+
}
265+
}
266+
}
267+
212268
impl PartialSignature {
213269
/// Serialize a PartialSignature.
214270
///
@@ -624,6 +680,62 @@ impl CPtr for PublicNonce {
624680
fn as_mut_c_ptr(&mut self) -> *mut Self::Target { self.as_mut_ptr() }
625681
}
626682

683+
impl fmt::LowerHex for PublicNonce {
684+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
685+
for b in self.serialize() {
686+
write!(f, "{:02x}", b)?;
687+
}
688+
Ok(())
689+
}
690+
}
691+
692+
impl fmt::Display for PublicNonce {
693+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
694+
}
695+
696+
impl core::str::FromStr for PublicNonce {
697+
type Err = ParseError;
698+
fn from_str(s: &str) -> Result<Self, Self::Err> {
699+
let mut res = [0u8; ffi::MUSIG_PUBNONCE_SERIALIZED_LEN];
700+
match from_hex(s, &mut res) {
701+
Ok(ffi::MUSIG_PUBNONCE_SERIALIZED_LEN) => PublicNonce::from_byte_array(&res),
702+
_ => Err(ParseError::MalformedArg),
703+
}
704+
}
705+
}
706+
707+
#[cfg(feature = "serde")]
708+
impl serde::Serialize for PublicNonce {
709+
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
710+
if s.is_human_readable() {
711+
s.collect_str(self)
712+
} else {
713+
s.serialize_bytes(&self.serialize()[..])
714+
}
715+
}
716+
}
717+
718+
#[cfg(feature = "serde")]
719+
impl<'de> serde::Deserialize<'de> for PublicNonce {
720+
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
721+
if d.is_human_readable() {
722+
d.deserialize_str(super::serde_util::FromStrVisitor::new(
723+
"a hex string representing a MuSig2 public nonce",
724+
))
725+
} else {
726+
d.deserialize_bytes(super::serde_util::BytesVisitor::new(
727+
"a raw MuSig2 public nonce",
728+
|slice| {
729+
let bytes: &[u8; ffi::MUSIG_PUBNONCE_SERIALIZED_LEN] =
730+
slice.try_into().map_err(|_| ParseError::MalformedArg)?;
731+
732+
Self::from_byte_array(bytes)
733+
},
734+
))
735+
}
736+
}
737+
}
738+
627739
impl PublicNonce {
628740
/// Serialize a PublicNonce
629741
pub fn serialize(&self) -> [u8; ffi::MUSIG_PUBNONCE_SERIALIZED_LEN] {
@@ -685,6 +797,62 @@ impl CPtr for AggregatedNonce {
685797
fn as_mut_c_ptr(&mut self) -> *mut Self::Target { self.as_mut_ptr() }
686798
}
687799

800+
impl fmt::LowerHex for AggregatedNonce {
801+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
802+
for b in self.serialize() {
803+
write!(f, "{:02x}", b)?;
804+
}
805+
Ok(())
806+
}
807+
}
808+
809+
impl fmt::Display for AggregatedNonce {
810+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
811+
}
812+
813+
impl core::str::FromStr for AggregatedNonce {
814+
type Err = ParseError;
815+
fn from_str(s: &str) -> Result<Self, Self::Err> {
816+
let mut res = [0u8; ffi::MUSIG_AGGNONCE_SERIALIZED_LEN];
817+
match from_hex(s, &mut res) {
818+
Ok(ffi::MUSIG_AGGNONCE_SERIALIZED_LEN) => AggregatedNonce::from_byte_array(&res),
819+
_ => Err(ParseError::MalformedArg),
820+
}
821+
}
822+
}
823+
824+
#[cfg(feature = "serde")]
825+
impl serde::Serialize for AggregatedNonce {
826+
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
827+
if s.is_human_readable() {
828+
s.collect_str(self)
829+
} else {
830+
s.serialize_bytes(&self.serialize()[..])
831+
}
832+
}
833+
}
834+
835+
#[cfg(feature = "serde")]
836+
impl<'de> serde::Deserialize<'de> for AggregatedNonce {
837+
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
838+
if d.is_human_readable() {
839+
d.deserialize_str(super::serde_util::FromStrVisitor::new(
840+
"a hex string representing a MuSig2 aggregated nonce",
841+
))
842+
} else {
843+
d.deserialize_bytes(super::serde_util::BytesVisitor::new(
844+
"a raw MuSig2 aggregated nonce",
845+
|slice| {
846+
let bytes: &[u8; ffi::MUSIG_AGGNONCE_SERIALIZED_LEN] =
847+
slice.try_into().map_err(|_| ParseError::MalformedArg)?;
848+
849+
Self::from_byte_array(bytes)
850+
},
851+
))
852+
}
853+
}
854+
}
855+
688856
impl AggregatedNonce {
689857
/// Combine received public nonces into a single aggregated nonce
690858
///

0 commit comments

Comments
 (0)