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 offset = array.len().saturating_sub(bytes.len().try_into()?);
29 array[offset..].copy_from_slice(bytes.as_bytes());
30 Ok(Uint::from_be_byte_array(array))
31 }
32}
33
34impl<'a, const LIMBS: usize> DecodeValue<'a> for Uint<LIMBS>
35where
36 Uint<LIMBS>: ArrayEncoding,
37{
38 type Error = der::Error;
39
40 fn decode_value<R: der::Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
41 Asn1UintRef::decode_value(reader, header)?.try_into()
42 }
43}
44
45impl<const LIMBS: usize> EncodeValue for Uint<LIMBS>
46where
47 Uint<LIMBS>: ArrayEncoding,
48{
49 fn value_len(&self) -> der::Result<Length> {
50 Ok(count_der_be_bytes(&self.limbs).into())
51 }
52
53 fn encode_value(&self, encoder: &mut impl der::Writer) -> der::Result<()> {
54 let array = self.to_be_byte_array();
55 Asn1UintRef::new(&array)?.encode_value(encoder)
56 }
57}
58
59impl<const LIMBS: usize> FixedTag for Uint<LIMBS>
60where
61 Uint<LIMBS>: ArrayEncoding,
62{
63 const TAG: Tag = Tag::Integer;
64}
65
66#[inline]
68#[allow(clippy::integer_division_remainder_used, reason = "needs triage")]
69pub(crate) fn count_der_be_bytes(limbs: &[Limb]) -> u32 {
70 let leading_zero_bytes = UintRef::new(limbs).leading_zeros() / 8;
72
73 let limb_index = limbs
75 .len()
76 .saturating_sub(1)
77 .saturating_sub(leading_zero_bytes as usize / Limb::BYTES);
78
79 let first_nonzero_byte = limbs.get(limb_index).cloned().map_or(0x00, |limb| {
81 limb.to_be_bytes()[leading_zero_bytes as usize % Limb::BYTES]
82 });
83
84 let needs_leading_zero = first_nonzero_byte >= 0x80;
86
87 #[allow(clippy::cast_possible_truncation)]
89 let max_len = (Limb::BYTES * limbs.len()) as u32;
90
91 if leading_zero_bytes == max_len {
93 1
95 } else {
96 max_len
97 .saturating_sub(leading_zero_bytes)
98 .wrapping_add(u32::from(needs_leading_zero))
99 }
100}
101
102#[cfg(feature = "alloc")]
103pub mod allocating {
104 use der::{DecodeValue, EncodeValue, FixedTag, Length, Tag, asn1::UintRef as Asn1UintRef};
105
106 use crate::{BoxedUint, encoding::der::count_der_be_bytes};
107
108 impl EncodeValue for BoxedUint {
109 fn value_len(&self) -> der::Result<Length> {
110 Ok(count_der_be_bytes(&self.limbs).into())
111 }
112
113 fn encode_value(&self, encoder: &mut impl der::Writer) -> der::Result<()> {
114 let array = self.to_be_bytes();
115 Asn1UintRef::new(&array)?.encode_value(encoder)
116 }
117 }
118
119 impl<'a> DecodeValue<'a> for BoxedUint {
120 type Error = der::Error;
121
122 fn decode_value<R: der::Reader<'a>>(
123 reader: &mut R,
124 header: der::Header,
125 ) -> der::Result<Self> {
126 let value = Asn1UintRef::decode_value(reader, header)?;
127
128 #[allow(clippy::cast_possible_truncation)]
129 let bits_precision = value.as_bytes().len() as u32 * 8;
130
131 let value = BoxedUint::from_be_slice(value.as_bytes(), bits_precision)
132 .map_err(|_| Asn1UintRef::TAG.value_error())?;
133 Ok(value)
134 }
135 }
136
137 impl FixedTag for BoxedUint {
138 const TAG: Tag = Tag::Integer;
139 }
140}
141
142#[cfg(test)]
143pub mod test {
144 use crate::{ArrayEncoding, BoxedUint, U128, Uint};
145 use der::{DecodeValue, EncodeValue, Header, Tag};
146
147 #[allow(clippy::cast_possible_truncation, clippy::panic_in_result_fn)]
148 fn assert_valid_uint_value_len<const LIMBS: usize>(n: &Uint<LIMBS>) -> der::Result<()>
149 where
150 Uint<LIMBS>: ArrayEncoding,
151 {
152 let mut buf = [0u8; 128];
153 let encoded_value = {
154 let mut writer = der::SliceWriter::new(&mut buf);
155 n.encode_value(&mut writer)?;
156 writer.finish()?
157 };
158
159 let computed_len: u32 = n.value_len()?.into();
160 let encoded_len: u32 = encoded_value.len() as u32;
161 assert_eq!(
162 computed_len, encoded_len,
163 "computed_len: {computed_len}, encoded_len: {encoded_len}, n:{n:?}"
164 );
165
166 let decoded = {
167 let mut reader = der::SliceReader::new(encoded_value)?;
168 let header = Header::new(Tag::Integer, encoded_value.len().try_into()?);
169 Uint::<LIMBS>::decode_value(&mut reader, header)?
170 };
171
172 assert_eq!(n, &decoded);
173 Ok(())
174 }
175
176 #[cfg(feature = "alloc")]
177 #[allow(clippy::cast_possible_truncation, clippy::panic_in_result_fn)]
178 fn assert_valid_boxeduint_value_len(n: &BoxedUint) -> der::Result<()> {
179 let mut buf = [0u8; 128];
180 let encoded_value = {
181 let mut writer = der::SliceWriter::new(&mut buf);
182 n.encode_value(&mut writer)?;
183 writer.finish()?
184 };
185
186 let computed_len: u32 = n.value_len()?.into();
187 let encoded_len: u32 = encoded_value.len() as u32;
188 assert_eq!(
189 computed_len, encoded_len,
190 "computed_len: {computed_len}, encoded_len: {encoded_len}, n:{n:?}"
191 );
192 let decoded = {
193 let mut reader = der::SliceReader::new(encoded_value)?;
194 let header = Header::new(Tag::Integer, encoded_value.len().try_into()?);
195 BoxedUint::decode_value(&mut reader, header)?
196 };
197
198 assert_eq!(n, &decoded);
199
200 Ok(())
201 }
202
203 fn assert_valid_value_len_hex(hex_uint: &str) {
204 let n = U128::from_str_radix_vartime(hex_uint, 16).expect("error decoding");
205 assert_valid_uint_value_len(&n).expect("error from der: Uint");
206
207 #[cfg(feature = "alloc")]
208 assert_valid_boxeduint_value_len(&BoxedUint::from(n)).expect("error from der: BoxedUint");
209 }
210 #[test]
211 fn encode_uint() {
212 assert_valid_value_len_hex("00");
213 assert_valid_value_len_hex("10");
214 assert_valid_value_len_hex("3210");
215
216 assert_valid_value_len_hex("00000000000000007fdcba9876543210");
217 assert_valid_value_len_hex("0000000000000000fedcba9876543210");
218 assert_valid_value_len_hex("0000000000000010fedcba9876543210");
219 assert_valid_value_len_hex("0000000000000080fedcba9876543210");
220
221 assert_valid_value_len_hex("0000008076543210fedcba9876543210");
222 assert_valid_value_len_hex("00dcba9876543210fedcba9876543210");
223 assert_valid_value_len_hex("0fdcba9876543210fedcba9876543210");
224 assert_valid_value_len_hex("7fdcba9876543210fedcba9876543210");
225 assert_valid_value_len_hex("fedcba9876543210fedcba9876543210");
226 }
227}