From 7d669fa538fc0698e459af313fb79e9d991e2f5a Mon Sep 17 00:00:00 2001 From: dishmaker <141624503+dishmaker@users.noreply.github.com> Date: Tue, 13 May 2025 13:44:05 +0200 Subject: [PATCH 1/2] dsa: reduce `Box<[u8]>` allocation in `SignatureEncoding::to_vec` --- dsa/src/lib.rs | 104 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 80 insertions(+), 24 deletions(-) diff --git a/dsa/src/lib.rs b/dsa/src/lib.rs index abc095dd..4da19c2b 100644 --- a/dsa/src/lib.rs +++ b/dsa/src/lib.rs @@ -109,43 +109,99 @@ impl Signature { pub fn s(&self) -> &NonZero { &self.s } + + fn to_boxed(&self) -> SignatureBoxed { + SignatureBoxed { + r: self.r.to_be_bytes(), + s: self.s.to_be_bytes(), + } + } + fn to_der_using_ref(&self) -> der::Result> { + self.to_boxed().to_ref()?.to_der() + } +} + +struct SignatureBoxed { + r: Box<[u8]>, + s: Box<[u8]>, +} +impl SignatureBoxed { + fn to_ref(&self) -> der::Result> { + Ok(SignatureRef { + r: UintRef::new(&self.r)?, + s: UintRef::new(&self.s)?, + }) + } +} + +struct SignatureRef<'a> { + r: UintRef<'a>, + s: UintRef<'a>, +} +impl<'a> SignatureRef<'a> { + fn to_owned(&self) -> der::Result { + let r = BoxedUint::from_be_slice(self.r.as_bytes(), self.r.as_bytes().len() as u32 * 8) + .map_err(|_| UintRef::TAG.value_error())?; + let s = BoxedUint::from_be_slice(self.s.as_bytes(), self.s.as_bytes().len() as u32 * 8) + .map_err(|_| UintRef::TAG.value_error())?; + + let r = NonZero::new(r) + .into_option() + .ok_or(UintRef::TAG.value_error())?; + let s = NonZero::new(s) + .into_option() + .ok_or(UintRef::TAG.value_error())?; + + Ok(Signature::from_components(r, s)) + } + + fn decode_value_inner>(reader: &mut R) -> der::Result { + Ok(SignatureRef { + r: UintRef::decode(reader)?, + s: UintRef::decode(reader)?, + }) + } +} + +impl<'a> DecodeValue<'a> for SignatureRef<'a> { + type Error = der::Error; + + fn decode_value>(reader: &mut R, header: Header) -> der::Result { + reader.read_nested(header.length, Self::decode_value_inner) + } +} + +impl EncodeValue for SignatureRef<'_> { + fn value_len(&self) -> der::Result { + self.r.encoded_len()? + self.s.encoded_len()? + } + + fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { + self.r.encode(writer)?; + self.s.encode(writer)?; + Ok(()) + } } +impl<'a> Sequence<'a> for SignatureRef<'a> {} impl<'a> DecodeValue<'a> for Signature { type Error = der::Error; fn decode_value>(reader: &mut R, header: Header) -> der::Result { - reader.read_nested(header.length, |reader| { - let r = UintRef::decode(reader)?; - let s = UintRef::decode(reader)?; - - let r = BoxedUint::from_be_slice(r.as_bytes(), r.as_bytes().len() as u32 * 8) - .map_err(|_| UintRef::TAG.value_error())?; - let s = BoxedUint::from_be_slice(s.as_bytes(), s.as_bytes().len() as u32 * 8) - .map_err(|_| UintRef::TAG.value_error())?; - - let r = NonZero::new(r) - .into_option() - .ok_or(UintRef::TAG.value_error())?; - let s = NonZero::new(s) - .into_option() - .ok_or(UintRef::TAG.value_error())?; - - Ok(Self::from_components(r, s)) - }) + let signature_ref = SignatureRef::decode_value(reader, header)?; + + signature_ref.to_owned() } } impl EncodeValue for Signature { fn value_len(&self) -> der::Result { - UintRef::new(&self.r.to_be_bytes())?.encoded_len()? - + UintRef::new(&self.s.to_be_bytes())?.encoded_len()? + // TODO: avoid Box<[u8]> allocation here + self.to_boxed().to_ref()?.value_len() } fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { - UintRef::new(&self.r.to_be_bytes())?.encode(writer)?; - UintRef::new(&self.s.to_be_bytes())?.encode(writer)?; - Ok(()) + self.to_boxed().to_ref()?.encode_value(writer) } } @@ -177,7 +233,7 @@ impl SignatureEncoding for Signature { } fn to_vec(&self) -> Vec { - self.to_der().expect("DER encoding error") + self.to_der_using_ref().expect("DER encoding error") } } From 864c3b6781f6d96bc282c8300559a263f289f2e5 Mon Sep 17 00:00:00 2001 From: dishmaker <141624503+dishmaker@users.noreply.github.com> Date: Tue, 13 May 2025 14:01:01 +0200 Subject: [PATCH 2/2] dsa: refactor: move `SignatureRef` to `signature_ref.rs` --- dsa/src/lib.rs | 73 +++---------------------------------- dsa/src/signature_ref.rs | 78 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 69 deletions(-) create mode 100644 dsa/src/signature_ref.rs diff --git a/dsa/src/lib.rs b/dsa/src/lib.rs index 4da19c2b..c0ed4152 100644 --- a/dsa/src/lib.rs +++ b/dsa/src/lib.rs @@ -65,6 +65,7 @@ use pkcs8::spki::ObjectIdentifier; mod components; mod generate; +mod signature_ref; mod signing_key; mod size; mod verifying_key; @@ -76,10 +77,10 @@ pub const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10040.4. use alloc::{boxed::Box, vec::Vec}; use pkcs8::der::{ - self, Decode, DecodeValue, Encode, EncodeValue, FixedTag, Header, Length, Reader, Sequence, - Writer, asn1::UintRef, + self, Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Writer, }; use signature::SignatureEncoding; +use signature_ref::{SignatureBoxed, SignatureRef}; /// Container of the DSA signature #[derive(Clone, Debug)] @@ -111,79 +112,13 @@ impl Signature { } fn to_boxed(&self) -> SignatureBoxed { - SignatureBoxed { - r: self.r.to_be_bytes(), - s: self.s.to_be_bytes(), - } + SignatureBoxed::new(self) } fn to_der_using_ref(&self) -> der::Result> { self.to_boxed().to_ref()?.to_der() } } -struct SignatureBoxed { - r: Box<[u8]>, - s: Box<[u8]>, -} -impl SignatureBoxed { - fn to_ref(&self) -> der::Result> { - Ok(SignatureRef { - r: UintRef::new(&self.r)?, - s: UintRef::new(&self.s)?, - }) - } -} - -struct SignatureRef<'a> { - r: UintRef<'a>, - s: UintRef<'a>, -} -impl<'a> SignatureRef<'a> { - fn to_owned(&self) -> der::Result { - let r = BoxedUint::from_be_slice(self.r.as_bytes(), self.r.as_bytes().len() as u32 * 8) - .map_err(|_| UintRef::TAG.value_error())?; - let s = BoxedUint::from_be_slice(self.s.as_bytes(), self.s.as_bytes().len() as u32 * 8) - .map_err(|_| UintRef::TAG.value_error())?; - - let r = NonZero::new(r) - .into_option() - .ok_or(UintRef::TAG.value_error())?; - let s = NonZero::new(s) - .into_option() - .ok_or(UintRef::TAG.value_error())?; - - Ok(Signature::from_components(r, s)) - } - - fn decode_value_inner>(reader: &mut R) -> der::Result { - Ok(SignatureRef { - r: UintRef::decode(reader)?, - s: UintRef::decode(reader)?, - }) - } -} - -impl<'a> DecodeValue<'a> for SignatureRef<'a> { - type Error = der::Error; - - fn decode_value>(reader: &mut R, header: Header) -> der::Result { - reader.read_nested(header.length, Self::decode_value_inner) - } -} - -impl EncodeValue for SignatureRef<'_> { - fn value_len(&self) -> der::Result { - self.r.encoded_len()? + self.s.encoded_len()? - } - - fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { - self.r.encode(writer)?; - self.s.encode(writer)?; - Ok(()) - } -} -impl<'a> Sequence<'a> for SignatureRef<'a> {} - impl<'a> DecodeValue<'a> for Signature { type Error = der::Error; diff --git a/dsa/src/signature_ref.rs b/dsa/src/signature_ref.rs new file mode 100644 index 00000000..f638a640 --- /dev/null +++ b/dsa/src/signature_ref.rs @@ -0,0 +1,78 @@ +use alloc::boxed::Box; +use crypto_bigint::{BoxedUint, NonZero}; +use pkcs8::der::{ + self, Decode, DecodeValue, Encode, EncodeValue, FixedTag, Header, Length, Reader, Sequence, + Writer, asn1::UintRef, +}; + +use crate::Signature; + +pub(crate) struct SignatureBoxed { + r: Box<[u8]>, + s: Box<[u8]>, +} +impl SignatureBoxed { + pub fn new(sig: &Signature) -> Self { + Self { + r: sig.r().to_be_bytes(), + s: sig.s().to_be_bytes(), + } + } + + pub fn to_ref(&self) -> der::Result> { + Ok(SignatureRef { + r: UintRef::new(&self.r)?, + s: UintRef::new(&self.s)?, + }) + } +} + +pub(crate) struct SignatureRef<'a> { + r: UintRef<'a>, + s: UintRef<'a>, +} +impl<'a> SignatureRef<'a> { + pub fn to_owned(&self) -> der::Result { + let r = BoxedUint::from_be_slice(self.r.as_bytes(), self.r.as_bytes().len() as u32 * 8) + .map_err(|_| UintRef::TAG.value_error())?; + let s = BoxedUint::from_be_slice(self.s.as_bytes(), self.s.as_bytes().len() as u32 * 8) + .map_err(|_| UintRef::TAG.value_error())?; + + let r = NonZero::new(r) + .into_option() + .ok_or(UintRef::TAG.value_error())?; + let s = NonZero::new(s) + .into_option() + .ok_or(UintRef::TAG.value_error())?; + + Ok(Signature::from_components(r, s)) + } + + fn decode_value_inner>(reader: &mut R) -> der::Result { + Ok(SignatureRef { + r: UintRef::decode(reader)?, + s: UintRef::decode(reader)?, + }) + } +} + +impl<'a> DecodeValue<'a> for SignatureRef<'a> { + type Error = der::Error; + + fn decode_value>(reader: &mut R, header: Header) -> der::Result { + reader.read_nested(header.length, Self::decode_value_inner) + } +} + +impl EncodeValue for SignatureRef<'_> { + fn value_len(&self) -> der::Result { + self.r.encoded_len()? + self.s.encoded_len()? + } + + fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { + self.r.encode(writer)?; + self.s.encode(writer)?; + Ok(()) + } +} +impl<'a> Sequence<'a> for SignatureRef<'a> {}