crypto_bigint/uint/encoding/
der.rs1use crate::{ArrayEncoding, Encoding, Limb, Uint, UintRef, hybrid_array::Array};
4use ::der::{
5 DecodeValue, EncodeValue, FixedTag, Length, Tag,
6 asn1::{AnyRef, UintRef as Asn1UintRef},
7};
8
9impl<'a, const LIMBS: usize> TryFrom<AnyRef<'a>> for Uint<LIMBS>
10where
11 Uint<LIMBS>: ArrayEncoding,
12{
13 type Error = der::Error;
14
15 fn try_from(any: AnyRef<'a>) -> der::Result<Uint<LIMBS>> {
16 Asn1UintRef::try_from(any)?.try_into()
17 }
18}
19
20impl<'a, const LIMBS: usize> TryFrom<Asn1UintRef<'a>> for Uint<LIMBS>
21where
22 Uint<LIMBS>: ArrayEncoding,
23{
24 type Error = der::Error;
25
26 fn try_from(bytes: Asn1UintRef<'a>) -> der::Result<Uint<LIMBS>> {
27 let mut array = Array::default();
28 let len = usize::try_from(bytes.len())?;
29 let offset = array
30 .len()
31 .checked_sub(len)
32 .ok_or_else(|| Tag::Integer.length_error())?;
33 let out = array
34 .get_mut(offset..)
35 .ok_or_else(|| Tag::Integer.length_error())?;
36
37 out.copy_from_slice(bytes.as_bytes());
38 Ok(Uint::from_be_byte_array(array))
39 }
40}
41
42impl<'a, const LIMBS: usize> DecodeValue<'a> for Uint<LIMBS>
43where
44 Uint<LIMBS>: ArrayEncoding,
45{
46 type Error = der::Error;
47
48 fn decode_value<R: der::Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
49 Asn1UintRef::decode_value(reader, header)?.try_into()
50 }
51}
52
53impl<const LIMBS: usize> EncodeValue for Uint<LIMBS>
54where
55 Uint<LIMBS>: ArrayEncoding,
56{
57 fn value_len(&self) -> der::Result<Length> {
58 Ok(count_der_be_bytes(&self.limbs).into())
59 }
60
61 fn encode_value(&self, encoder: &mut impl der::Writer) -> der::Result<()> {
62 let array = self.to_be_byte_array();
63 Asn1UintRef::new(&array)?.encode_value(encoder)
64 }
65}
66
67impl<const LIMBS: usize> FixedTag for Uint<LIMBS>
68where
69 Uint<LIMBS>: ArrayEncoding,
70{
71 const TAG: Tag = Tag::Integer;
72}
73
74#[inline]
76#[allow(clippy::integer_division_remainder_used, reason = "needs triage")]
77pub(crate) fn count_der_be_bytes(limbs: &[Limb]) -> u32 {
78 let leading_zero_bytes = UintRef::new(limbs).leading_zeros() / 8;
80
81 let limb_index = limbs
83 .len()
84 .saturating_sub(1)
85 .saturating_sub(leading_zero_bytes as usize / Limb::BYTES);
86
87 let first_nonzero_byte = limbs.get(limb_index).cloned().map_or(0x00, |limb| {
89 limb.to_be_bytes()[leading_zero_bytes as usize % Limb::BYTES]
90 });
91
92 let needs_leading_zero = first_nonzero_byte >= 0x80;
94
95 let max_len = Limb::BYTES
97 .checked_mul(limbs.len())
98 .and_then(|bytes| u32::try_from(bytes).ok())
99 .expect("u32 overflow"); if leading_zero_bytes == max_len {
103 1
105 } else {
106 max_len
107 .saturating_sub(leading_zero_bytes)
108 .wrapping_add(u32::from(needs_leading_zero))
109 }
110}
111
112#[cfg(feature = "alloc")]
113pub mod allocating {
114 use super::count_der_be_bytes;
115 use crate::{BoxedUint, bitlen};
116 use der::{DecodeValue, EncodeValue, FixedTag, Length, Tag, asn1::UintRef as Asn1UintRef};
117
118 impl EncodeValue for BoxedUint {
119 fn value_len(&self) -> der::Result<Length> {
120 Ok(count_der_be_bytes(&self.limbs).into())
121 }
122
123 fn encode_value(&self, encoder: &mut impl der::Writer) -> der::Result<()> {
124 let array = self.to_be_bytes();
125 Asn1UintRef::new(&array)?.encode_value(encoder)
126 }
127 }
128
129 impl<'a> DecodeValue<'a> for BoxedUint {
130 type Error = der::Error;
131
132 fn decode_value<R: der::Reader<'a>>(
133 reader: &mut R,
134 header: der::Header,
135 ) -> der::Result<Self> {
136 let value = Asn1UintRef::decode_value(reader, header)?;
137 let bits_precision = bitlen::from_bytes(value.as_bytes().len());
138
139 let value = BoxedUint::from_be_slice(value.as_bytes(), bits_precision)
140 .map_err(|_| Asn1UintRef::TAG.value_error())?;
141 Ok(value)
142 }
143 }
144
145 impl FixedTag for BoxedUint {
146 const TAG: Tag = Tag::Integer;
147 }
148}
149
150#[cfg(test)]
151pub mod test {
152 use crate::{ArrayEncoding, U128, Uint};
153 use der::{DecodeValue, EncodeValue, Header, Tag};
154 extern crate std;
155
156 #[cfg(feature = "alloc")]
157 use crate::BoxedUint;
158
159 #[allow(clippy::cast_possible_truncation, clippy::panic_in_result_fn)]
160 fn assert_valid_uint_value_len<const LIMBS: usize>(n: &Uint<LIMBS>) -> der::Result<()>
161 where
162 Uint<LIMBS>: ArrayEncoding,
163 {
164 let mut buf = [0u8; 128];
165 let encoded_value = {
166 let mut writer = der::SliceWriter::new(&mut buf);
167 n.encode_value(&mut writer)?;
168 writer.finish()?
169 };
170
171 let computed_len: u32 = n.value_len()?.into();
172 let encoded_len: u32 = encoded_value.len() as u32;
173 assert_eq!(
174 computed_len, encoded_len,
175 "computed_len: {computed_len}, encoded_len: {encoded_len}, n:{n:?}"
176 );
177
178 let decoded = {
179 let mut reader = der::SliceReader::new(encoded_value)?;
180 let header = Header::new(Tag::Integer, encoded_value.len().try_into()?);
181 Uint::<LIMBS>::decode_value(&mut reader, header)?
182 };
183
184 assert_eq!(n, &decoded);
185 Ok(())
186 }
187
188 #[cfg(feature = "alloc")]
189 #[allow(clippy::cast_possible_truncation, clippy::panic_in_result_fn)]
190 fn assert_valid_boxeduint_value_len(n: &BoxedUint) -> der::Result<()> {
191 let mut buf = [0u8; 128];
192 let encoded_value = {
193 let mut writer = der::SliceWriter::new(&mut buf);
194 n.encode_value(&mut writer)?;
195 writer.finish()?
196 };
197
198 let computed_len: u32 = n.value_len()?.into();
199 let encoded_len: u32 = encoded_value.len() as u32;
200 assert_eq!(
201 computed_len, encoded_len,
202 "computed_len: {computed_len}, encoded_len: {encoded_len}, n:{n:?}"
203 );
204 let decoded = {
205 let mut reader = der::SliceReader::new(encoded_value)?;
206 let header = Header::new(Tag::Integer, encoded_value.len().try_into()?);
207 BoxedUint::decode_value(&mut reader, header)?
208 };
209
210 assert_eq!(n, &decoded);
211
212 Ok(())
213 }
214
215 fn assert_valid_value_len_hex(hex_uint: &str) {
216 let n = U128::from_str_radix_vartime(hex_uint, 16).expect("error decoding");
217 assert_valid_uint_value_len(&n).expect("error from der: Uint");
218
219 #[cfg(feature = "alloc")]
220 assert_valid_boxeduint_value_len(&BoxedUint::from(n)).expect("error from der: BoxedUint");
221 }
222 #[test]
223 fn encode_uint() {
224 assert_valid_value_len_hex("00");
225 assert_valid_value_len_hex("10");
226 assert_valid_value_len_hex("3210");
227
228 assert_valid_value_len_hex("00000000000000007fdcba9876543210");
229 assert_valid_value_len_hex("0000000000000000fedcba9876543210");
230 assert_valid_value_len_hex("0000000000000010fedcba9876543210");
231 assert_valid_value_len_hex("0000000000000080fedcba9876543210");
232
233 assert_valid_value_len_hex("0000008076543210fedcba9876543210");
234 assert_valid_value_len_hex("00dcba9876543210fedcba9876543210");
235 assert_valid_value_len_hex("0fdcba9876543210fedcba9876543210");
236 assert_valid_value_len_hex("7fdcba9876543210fedcba9876543210");
237 assert_valid_value_len_hex("fedcba9876543210fedcba9876543210");
238 }
239
240 #[test]
241 fn fixed_uint_rejects_oversized_integer_without_panic() {
242 use der::Decode;
243
244 let mut der = vec![0x02, 17, 0x01];
245 der.extend_from_slice(&[0u8; 16]);
246
247 assert!(U128::from_der(&der).is_err());
248 }
249}