From 112d2f4a41c10f0ee0258e5b645b6188a9098395 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sun, 3 May 2026 09:15:11 -0600 Subject: [PATCH] ed25519: use `serdect` for serde support Follows suit with `serde` support in other RustCrypto crates by using `serdect` to implement `Serialize` and `Deserialize`, replacing the previous use of `serde_bytes`. These serializers use the `serdect::array` serializers which use efficient format-specific byte encodings (albeit with a length prefix) when serializing to binary formats, or a hex encoding with human readable formats like JSON and TOML. --- Cargo.lock | 3 +- ed25519/Cargo.toml | 5 +-- ed25519/src/lib.rs | 27 ++++++++++-- ed25519/src/serde.rs | 98 -------------------------------------------- 4 files changed, 27 insertions(+), 106 deletions(-) delete mode 100644 ed25519/src/serde.rs diff --git a/Cargo.lock b/Cargo.lock index 9e8467b9..3e3a8553 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -478,8 +478,7 @@ dependencies = [ "hex-literal", "pkcs8", "rand_core 0.9.5", - "serde", - "serde_bytes", + "serdect", "signature 3.0.0", "zerocopy", "zeroize", diff --git a/ed25519/Cargo.toml b/ed25519/Cargo.toml index accd817f..4d627608 100644 --- a/ed25519/Cargo.toml +++ b/ed25519/Cargo.toml @@ -22,8 +22,7 @@ signature = { version = "3", default-features = false } # optional dependencies pkcs8 = { version = "0.11", optional = true } -serde = { version = "1", optional = true, default-features = false } -serde_bytes = { version = "0.11", optional = true, default-features = false } +serdect = { version = "0.4", optional = true, default-features = false } zeroize = { version = "1", optional = true, default-features = false } zerocopy = { version = "0.8", optional = true, features = ["derive"] } @@ -37,7 +36,7 @@ rand_core = { version = "0.9", features = ["std"] } default = ["alloc"] alloc = ["pkcs8?/alloc"] pem = ["alloc", "pkcs8/pem"] -serde_bytes = ["serde", "dep:serde_bytes"] +serde = ["dep:serdect"] [lints] workspace = true diff --git a/ed25519/src/lib.rs b/ed25519/src/lib.rs index af481d62..21c3ef6a 100644 --- a/ed25519/src/lib.rs +++ b/ed25519/src/lib.rs @@ -260,9 +260,6 @@ mod hex; #[cfg(feature = "pkcs8")] pub mod pkcs8; -#[cfg(feature = "serde")] -mod serde; - pub use signature::{self, Error, SignatureEncoding}; #[cfg(feature = "pkcs8")] @@ -278,6 +275,8 @@ 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::{ @@ -451,6 +450,28 @@ 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 deleted file mode 100644 index 51f7b8c2..00000000 --- a/ed25519/src/serde.rs +++ /dev/null @@ -1,98 +0,0 @@ -//! `serde` support. - -use crate::{Signature, SignatureBytes}; -use ::serde::{Deserialize, Serialize, de, ser}; -use core::fmt; - -impl Serialize for Signature { - fn serialize(&self, serializer: S) -> Result { - use ser::SerializeTuple; - - let mut seq = serializer.serialize_tuple(Signature::BYTE_SIZE)?; - - for byte in self.to_bytes() { - seq.serialize_element(&byte)?; - } - - seq.end() - } -} - -// serde lacks support for deserializing arrays larger than 32-bytes -// see: -impl<'de> Deserialize<'de> for Signature { - fn deserialize>(deserializer: D) -> Result { - struct ByteArrayVisitor; - - impl<'de> de::Visitor<'de> for ByteArrayVisitor { - type Value = [u8; Signature::BYTE_SIZE]; - - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("bytestring of length 64") - } - - fn visit_seq(self, mut seq: A) -> Result<[u8; Signature::BYTE_SIZE], A::Error> - where - A: de::SeqAccess<'de>, - { - use de::Error; - let mut arr = [0u8; Signature::BYTE_SIZE]; - - for (i, byte) in arr.iter_mut().enumerate() { - *byte = seq - .next_element()? - .ok_or_else(|| Error::invalid_length(i, &self))?; - } - - Ok(arr) - } - } - - deserializer - .deserialize_tuple(Signature::BYTE_SIZE, ByteArrayVisitor) - .map(Into::into) - } -} - -#[cfg(feature = "serde_bytes")] -impl serde_bytes::Serialize for Signature { - fn serialize(&self, serializer: S) -> Result - where - S: serde::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) - } -}