From b0a3492fa6b91ec652d32896c648b51644790911 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 5 May 2026 15:00:28 -0600 Subject: [PATCH] ed25519: add back `serde_bytes` support Since `serdect` changes the wire format, this should at least provide backwards compatibility for `serde_bytes` users. --- Cargo.lock | 1 + ed25519/Cargo.toml | 2 ++ ed25519/src/lib.rs | 37 ++++------------------- ed25519/src/serde.rs | 70 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 31 deletions(-) create mode 100644 ed25519/src/serde.rs diff --git a/Cargo.lock b/Cargo.lock index d4691cda..6f93fc30 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -477,6 +477,7 @@ version = "3.0.0" dependencies = [ "hex-literal", "pkcs8", + "serde_bytes", "serdect", "signature", "zerocopy", diff --git a/ed25519/Cargo.toml b/ed25519/Cargo.toml index 2a548e71..3e19b7f5 100644 --- a/ed25519/Cargo.toml +++ b/ed25519/Cargo.toml @@ -23,6 +23,7 @@ signature = { version = "3", default-features = false } # optional dependencies pkcs8 = { version = "0.11", optional = true } serdect = { version = "0.4", optional = true, default-features = false } +serde_bytes = { version = "0.11", optional = true, default-features = false } zeroize = { version = "1", optional = true, default-features = false } zerocopy = { version = "0.8", optional = true, features = ["derive"] } @@ -36,6 +37,7 @@ default = ["alloc"] alloc = ["pkcs8?/alloc", "signature/alloc"] pem = ["alloc", "pkcs8/pem"] serde = ["dep:serdect"] +serde_bytes = ["serde", "dep:serde_bytes"] [lints] workspace = true diff --git a/ed25519/src/lib.rs b/ed25519/src/lib.rs index 1208e5b6..abbfb23c 100644 --- a/ed25519/src/lib.rs +++ b/ed25519/src/lib.rs @@ -255,11 +255,13 @@ #[cfg(feature = "alloc")] extern crate alloc; -mod hex; - #[cfg(feature = "pkcs8")] pub mod pkcs8; +mod hex; +#[cfg(feature = "serde")] +mod serde; + pub use signature::{self, Error, SignatureEncoding}; #[cfg(feature = "pkcs8")] @@ -275,20 +277,15 @@ use core::fmt; #[cfg(feature = "alloc")] use alloc::vec::Vec; -#[cfg(feature = "serde")] -use serdect::serde::{Deserialize, Serialize, de, ser}; - #[cfg(all(feature = "alloc", feature = "pkcs8"))] use pkcs8::spki::{ SignatureBitStringEncoding, der::{self, asn1::BitString}, }; - -#[cfg(feature = "zeroize")] -use zeroize::Zeroize; - #[cfg(feature = "zerocopy")] use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned}; +#[cfg(feature = "zeroize")] +use zeroize::Zeroize; /// Size of a single component of an Ed25519 signature. const COMPONENT_SIZE: usize = 32; @@ -450,28 +447,6 @@ impl fmt::Display for Signature { } } -#[cfg(feature = "serde")] -impl Serialize for Signature { - fn serialize(&self, serializer: S) -> Result - where - S: ser::Serializer, - { - serdect::array::serialize_hex_upper_or_bin(&self.to_bytes(), serializer) - } -} - -#[cfg(feature = "serde")] -impl<'de> Deserialize<'de> for Signature { - fn deserialize(deserializer: D) -> Result - where - D: de::Deserializer<'de>, - { - let mut bytes = [0u8; Signature::BYTE_SIZE]; - serdect::array::deserialize_hex_or_bin(&mut bytes, deserializer)?; - Ok(bytes.into()) - } -} - #[cfg(feature = "zeroize")] impl Zeroize for Signature { fn zeroize(&mut self) { diff --git a/ed25519/src/serde.rs b/ed25519/src/serde.rs new file mode 100644 index 00000000..4d8d1597 --- /dev/null +++ b/ed25519/src/serde.rs @@ -0,0 +1,70 @@ +//! `serde` support including optional `serde_bytes` support. + +use crate::{Signature, SignatureBytes}; +use core::fmt; +use serdect::serde::{Deserialize, Serialize, de, ser}; + +#[cfg(feature = "serde")] +impl Serialize for Signature { + fn serialize(&self, serializer: S) -> Result + where + S: ser::Serializer, + { + serdect::array::serialize_hex_upper_or_bin(&self.to_bytes(), serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for Signature { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + let mut bytes = [0u8; Signature::BYTE_SIZE]; + serdect::array::deserialize_hex_or_bin(&mut bytes, deserializer)?; + Ok(bytes.into()) + } +} + +#[cfg(feature = "serde_bytes")] +impl serde_bytes::Serialize for Signature { + fn serialize(&self, serializer: S) -> Result + where + S: ser::Serializer, + { + serializer.serialize_bytes(&self.to_bytes()) + } +} + +#[cfg(feature = "serde_bytes")] +impl<'de> serde_bytes::Deserialize<'de> for Signature { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + struct ByteArrayVisitor; + + impl de::Visitor<'_> for ByteArrayVisitor { + type Value = SignatureBytes; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("bytestring of length 64") + } + + fn visit_bytes(self, bytes: &[u8]) -> Result + where + E: de::Error, + { + use de::Error; + + bytes + .try_into() + .map_err(|_| Error::invalid_length(bytes.len(), &self)) + } + } + + deserializer + .deserialize_bytes(ByteArrayVisitor) + .map(Into::into) + } +}