diff --git a/Cargo.toml b/Cargo.toml index e072e9d..5daa846 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,9 @@ zeroize = { version = "1", default-features = false, features = ["derive"] } rkyv = { version = "0.7", optional = true, default-features = false } bytecheck = { version = "0.6", optional = true, default-features = false } rayon = { version = "1.8", optional = true } +serde = { version = "1.0.210", optional = true } +bs58 = { version = "0.4.0" , optional = true } +serde_json = { version = "1.0.128", optional = true } [dev-dependencies] rand = "0.8" @@ -34,3 +37,4 @@ rkyv-impl = [ "bytecheck", ] parallel = ["dep:rayon"] +serde = ["dep:serde", "bs58", "serde_json"] diff --git a/src/lib.rs b/src/lib.rs index f71e1f8..89c77c0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,6 +21,9 @@ pub use keys::{ }; pub use signatures::{MultisigSignature, Signature}; +#[cfg(feature = "serde")] +mod serde_support; + #[cfg(feature = "rkyv-impl")] pub use crate::keys::{ public::{ diff --git a/src/serde_support.rs b/src/serde_support.rs new file mode 100644 index 0000000..94fa68d --- /dev/null +++ b/src/serde_support.rs @@ -0,0 +1,176 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) DUSK NETWORK. All rights reserved. + +extern crate alloc; + +use alloc::format; +use alloc::string::String; + +use bs58; +use dusk_bytes::Serializable; +use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; + +use crate::{MultisigPublicKey, MultisigSignature, PublicKey, SecretKey, Signature}; + +impl Serialize for PublicKey { + fn serialize( + &self, + serializer: S, + ) -> Result { + let s = bs58::encode(self.to_bytes()).into_string(); + serializer.serialize_str(&s) + } +} + +impl<'de> Deserialize<'de> for PublicKey { + fn deserialize>( + deserializer: D, + ) -> Result { + let s = String::deserialize(deserializer)?; + let mut bytes: [u8; Self::SIZE] = [0; Self::SIZE]; + match bs58::decode(&s).into(&mut bytes) { + Ok(n) => { + if n != Self::SIZE { + return Err(de::Error::custom( + "failed to deserialize PublicKey", + )); + } + } + Err(err) => return Err(de::Error::custom(format!("{err:?}"))), + } + let pubk = PublicKey::from_bytes(&bytes) + .map_err(|err| de::Error::custom(format!("{err:?}")))?; + Ok(pubk) + } +} + +impl Serialize for MultisigPublicKey { + fn serialize( + &self, + serializer: S, + ) -> Result { + let s = bs58::encode(self.to_bytes()).into_string(); + serializer.serialize_str(&s) + } +} + +impl<'de> Deserialize<'de> for MultisigPublicKey { + fn deserialize>( + deserializer: D, + ) -> Result { + let s = String::deserialize(deserializer)?; + let mut bytes: [u8; Self::SIZE] = [0; Self::SIZE]; + match bs58::decode(&s).into(&mut bytes) { + Ok(n) => { + if n != Self::SIZE { + return Err(de::Error::custom( + "failed to deserialize MultisigPublicKey", + )); + } + } + Err(err) => return Err(de::Error::custom(format!("{err:?}"))), + } + let pubk = MultisigPublicKey::from_bytes(&bytes) + .map_err(|err| de::Error::custom(format!("{err:?}")))?; + Ok(pubk) + } +} + +impl Serialize for Signature { + fn serialize( + &self, + serializer: S, + ) -> Result { + let s = bs58::encode(self.to_bytes()).into_string(); + serializer.serialize_str(&s) + } +} + +impl<'de> Deserialize<'de> for Signature { + fn deserialize>( + deserializer: D, + ) -> Result { + let s = String::deserialize(deserializer)?; + let mut bytes: [u8; Self::SIZE] = [0; Self::SIZE]; + match bs58::decode(&s).into(&mut bytes) { + Ok(n) => { + if n != Self::SIZE { + return Err(de::Error::custom( + "failed to deserialize Signature", + )); + } + } + Err(err) => return Err(de::Error::custom(format!("{err:?}"))), + } + let pubk = Signature::from_bytes(&bytes) + .map_err(|err| de::Error::custom(format!("{err:?}")))?; + Ok(pubk) + } +} + +impl Serialize for MultisigSignature { + fn serialize( + &self, + serializer: S, + ) -> Result { + let s = bs58::encode(self.to_bytes()).into_string(); + serializer.serialize_str(&s) + } +} + +impl<'de> Deserialize<'de> for MultisigSignature { + fn deserialize>( + deserializer: D, + ) -> Result { + let s = String::deserialize(deserializer)?; + let mut bytes: [u8; Self::SIZE] = [0; Self::SIZE]; + match bs58::decode(&s).into(&mut bytes) { + Ok(n) => { + if n != Self::SIZE { + return Err(de::Error::custom( + "failed to deserialize MultisigSignature", + )); + } + } + Err(err) => return Err(de::Error::custom(format!("{err:?}"))), + } + let pubk = MultisigSignature::from_bytes(&bytes) + .map_err(|err| de::Error::custom(format!("{err:?}")))?; + Ok(pubk) + } +} + +impl Serialize for SecretKey { + fn serialize( + &self, + serializer: S, + ) -> Result { + let s = bs58::encode(self.to_bytes()).into_string(); + serializer.serialize_str(&s) + } +} + +impl<'de> Deserialize<'de> for SecretKey { + fn deserialize>( + deserializer: D, + ) -> Result { + let s = String::deserialize(deserializer)?; + let mut bytes: [u8; Self::SIZE] = [0; Self::SIZE]; + match bs58::decode(&s).into(&mut bytes) { + Ok(n) => { + if n != Self::SIZE { + return Err(de::Error::custom( + "failed to deserialize SecretKey", + )); + } + } + Err(err) => return Err(de::Error::custom(format!("{err:?}"))), + } + let pubk = SecretKey::from_bytes(&bytes) + .map_err(|err| de::Error::custom(format!("{err:?}")))?; + Ok(pubk) + } +} diff --git a/tests/serde.rs b/tests/serde.rs new file mode 100644 index 0000000..42f5b4f --- /dev/null +++ b/tests/serde.rs @@ -0,0 +1,57 @@ +#[cfg(feature = "serde")] +mod tests { + use bls12_381_bls::{MultisigPublicKey, PublicKey, SecretKey}; + use rand::rngs::StdRng; + use rand::SeedableRng; + + #[test] + fn public_key() { + let mut rng = StdRng::seed_from_u64(0xbeef); + let pk = PublicKey::from(&SecretKey::random(&mut rng)); + let ser = serde_json::to_string(&pk); + let deser = serde_json::from_str(&ser.unwrap()); + assert_eq!(pk, deser.unwrap()); + } + + #[test] + fn multisig_public_key() { + let mut rng = StdRng::seed_from_u64(0xbeef); + let pk = MultisigPublicKey::aggregate(&[PublicKey::from( + &SecretKey::random(&mut rng), + )]) + .unwrap(); + let ser = serde_json::to_string(&pk); + let deser = serde_json::from_str(&ser.unwrap()); + assert_eq!(pk, deser.unwrap()); + } + + #[test] + fn signature() { + let mut rng = StdRng::seed_from_u64(0xbeef); + let sk = SecretKey::random(&mut rng); + let signature = sk.sign(b"a message"); + let ser = serde_json::to_string(&signature).unwrap(); + let deser = serde_json::from_str(&ser).unwrap(); + assert_eq!(signature, deser); + } + + #[test] + fn multisig_signature() { + let mut rng = StdRng::seed_from_u64(0xbeef); + let sk = SecretKey::random(&mut rng); + let pk = PublicKey::from(&sk); + let signature = sk.sign_multisig(&pk, b"a message"); + let ser = serde_json::to_string(&signature).unwrap(); + let deser = serde_json::from_str(&ser).unwrap(); + assert_eq!(signature, deser); + } + + #[test] + fn secret_key() { + let mut rng = StdRng::seed_from_u64(0xbeef); + let sk = SecretKey::random(&mut rng); + let ser = serde_json::to_string(&sk).unwrap(); + let deser = serde_json::from_str(&ser).unwrap(); + assert_eq!(sk, deser); + } +}