Skip to content

Commit 6100c6d

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 c668f8e commit 6100c6d

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

@@ -222,6 +222,62 @@ impl CPtr for PartialSignature {
222222
fn as_mut_c_ptr(&mut self) -> *mut Self::Target { self.as_mut_ptr() }
223223
}
224224

225+
impl fmt::LowerHex for PartialSignature {
226+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
227+
for b in self.serialize() {
228+
write!(f, "{:02x}", b)?;
229+
}
230+
Ok(())
231+
}
232+
}
233+
234+
impl fmt::Display for PartialSignature {
235+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
236+
}
237+
238+
impl core::str::FromStr for PartialSignature {
239+
type Err = ParseError;
240+
fn from_str(s: &str) -> Result<Self, Self::Err> {
241+
let mut res = [0u8; ffi::MUSIG_PART_SIG_SERIALIZED_LEN];
242+
match from_hex(s, &mut res) {
243+
Ok(ffi::MUSIG_PART_SIG_SERIALIZED_LEN) => PartialSignature::from_byte_array(&res),
244+
_ => Err(ParseError::MalformedArg),
245+
}
246+
}
247+
}
248+
249+
#[cfg(feature = "serde")]
250+
impl serde::Serialize for PartialSignature {
251+
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
252+
if s.is_human_readable() {
253+
s.collect_str(self)
254+
} else {
255+
s.serialize_bytes(&self.serialize()[..])
256+
}
257+
}
258+
}
259+
260+
#[cfg(feature = "serde")]
261+
impl<'de> serde::Deserialize<'de> for PartialSignature {
262+
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
263+
if d.is_human_readable() {
264+
d.deserialize_str(super::serde_util::FromStrVisitor::new(
265+
"a hex string representing a MuSig2 partial signature",
266+
))
267+
} else {
268+
d.deserialize_bytes(super::serde_util::BytesVisitor::new(
269+
"a raw MuSig2 partial signature",
270+
|slice| {
271+
let bytes: &[u8; ffi::MUSIG_PART_SIG_SERIALIZED_LEN] =
272+
slice.try_into().map_err(|_| ParseError::MalformedArg)?;
273+
274+
Self::from_byte_array(bytes)
275+
},
276+
))
277+
}
278+
}
279+
}
280+
225281
impl PartialSignature {
226282
/// Serialize a PartialSignature as a byte array.
227283
pub fn serialize(&self) -> [u8; ffi::MUSIG_PART_SIG_SERIALIZED_LEN] {
@@ -635,6 +691,62 @@ impl CPtr for PublicNonce {
635691
fn as_mut_c_ptr(&mut self) -> *mut Self::Target { self.as_mut_ptr() }
636692
}
637693

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

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

0 commit comments

Comments
 (0)