From fc67af817ce3f0c4a35d3d3ec177e357c8bad247 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sun, 24 Aug 2025 12:44:06 +0200 Subject: [PATCH] Allow `serde` without `alloc` --- Cargo.lock | 1 + elliptic-curve/Cargo.toml | 3 ++- elliptic-curve/src/public_key.rs | 29 ++++++++++++++++++++++++++++- 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e6d011ed..8667350e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -197,6 +197,7 @@ version = "0.14.0-rc.12" dependencies = [ "base16ct", "crypto-bigint", + "der", "digest", "ff", "group", diff --git a/elliptic-curve/Cargo.toml b/elliptic-curve/Cargo.toml index 7fb6bf2e..e313cfb3 100644 --- a/elliptic-curve/Cargo.toml +++ b/elliptic-curve/Cargo.toml @@ -34,6 +34,7 @@ pem-rfc7468 = { version = "1.0.0-rc.2", optional = true, features = ["alloc"] } pkcs8 = { version = "0.11.0-rc.6", optional = true, default-features = false } sec1 = { version = "0.8.0-rc.8", optional = true, features = ["subtle", "zeroize"] } serdect = { version = "0.3", optional = true, default-features = false, features = ["alloc"] } +der = { version = "0.8.0-rc.8", default-features = false } [dev-dependencies] hex-literal = "1" @@ -64,7 +65,7 @@ ecdh = ["arithmetic", "digest", "dep:hkdf"] group = ["dep:group", "ff"] pkcs8 = ["dep:pkcs8", "sec1"] pem = ["dep:pem-rfc7468", "alloc", "arithmetic", "pkcs8/pem", "sec1/pem"] -serde = ["dep:serdect", "alloc", "pkcs8", "sec1/serde"] +serde = ["dep:serdect", "pkcs8", "sec1/serde"] [package.metadata.docs.rs] features = ["bits", "ecdh", "pem", "std"] diff --git a/elliptic-curve/src/public_key.rs b/elliptic-curve/src/public_key.rs index f0e4a163..4379cb9a 100644 --- a/elliptic-curve/src/public_key.rs +++ b/elliptic-curve/src/public_key.rs @@ -425,6 +425,28 @@ where } } +#[cfg(feature = "serde")] +impl PublicKey +where + C: AssociatedOid + CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, +{ + /// Encode this [`PublicKey`] as der bytes, placing the result in `output`. This function + /// returns a slice containing the encoded DER bytes. + fn encode_as_der<'buf>(&self, output: &'buf mut [u8]) -> der::Result<&'buf [u8]> { + let public_key_bytes = self.to_encoded_point(false); + let subject_public_key = der::asn1::BitStringRef::new(0, public_key_bytes.as_bytes())?; + + let spki = pkcs8::SubjectPublicKeyInfo { + algorithm: Self::ALGORITHM_IDENTIFIER, + subject_public_key, + }; + + der::Encode::encode_to_slice(&spki, output) + } +} + #[cfg(all(feature = "alloc", feature = "pkcs8"))] impl EncodePublicKey for PublicKey where @@ -436,6 +458,7 @@ where let public_key_bytes = self.to_encoded_point(false); let subject_public_key = der::asn1::BitStringRef::new(0, public_key_bytes.as_bytes())?; + // TODO: use `encode_as_der` here? pkcs8::SubjectPublicKeyInfo { algorithm: Self::ALGORITHM_IDENTIFIER, subject_public_key, @@ -483,7 +506,11 @@ where where S: ser::Serializer, { - let der = self.to_public_key_der().map_err(ser::Error::custom)?; + // TODO: can we determine DER encoding length up-front? Using `MockCurve` gives + // 91 bytes of output, but it feels like that depends on the curve that is being + // used here. + let mut buf = [0u8; 91]; + let der = self.encode_as_der(&mut buf).map_err(ser::Error::custom)?; serdect::slice::serialize_hex_upper_or_bin(&der, serializer) } }