1//! Unsigned integer decoders/encoders.
23use crate::{Encoder, Length, Result, Tag};
45/// Decode an unsigned integer into a big endian byte slice with all leading
6/// zeroes removed.
7///
8/// Returns a byte array of the requested size containing a big endian integer.
9pub(super) fn decode_to_slice(bytes: &[u8]) -> Result<&[u8]> {
10// The `INTEGER` type always encodes a signed value, so for unsigned
11 // values the leading `0x00` byte may need to be removed.
12 //
13 // We also disallow a leading byte which would overflow a signed ASN.1
14 // integer (since we're decoding an unsigned integer).
15 // We expect all such cases to have a leading `0x00` byte.
16match bytes {
17 [] => Err(Tag::Integer.non_canonical_error()),
18 [0] => Ok(bytes),
19 [0, byte, ..] if *byte < 0x80 => Err(Tag::Integer.non_canonical_error()),
20 [0, rest @ ..] => Ok(rest),
21 [byte, ..] if *byte >= 0x80 => Err(Tag::Integer.value_error()),
22_ => Ok(bytes),
23 }
24}
2526/// Decode an unsigned integer into a byte array of the requested size
27/// containing a big endian integer.
28pub(super) fn decode_to_array<const N: usize>(bytes: &[u8]) -> Result<[u8; N]> {
29let input = decode_to_slice(bytes)?;
3031// Input has leading zeroes removed, so we need to add them back
32let mut output = [0u8; N];
33 output[N.saturating_sub(input.len())..].copy_from_slice(input);
34Ok(output)
35}
3637/// Encode the given big endian bytes representing an integer as ASN.1 DER.
38pub(super) fn encode_bytes(encoder: &mut Encoder<'_>, bytes: &[u8]) -> Result<()> {
39let bytes = strip_leading_zeroes(bytes);
4041if needs_leading_zero(bytes) {
42 encoder.byte(0)?;
43 }
4445 encoder.bytes(bytes)
46}
4748/// Get the encoded length for the given unsigned integer serialized as bytes.
49#[inline]
50pub(super) fn encoded_len(bytes: &[u8]) -> Result<Length> {
51let bytes = strip_leading_zeroes(bytes);
52 Length::try_from(bytes.len())? + needs_leading_zero(bytes) as u8
53}
5455/// Strip the leading zeroes from the given byte slice
56pub(super) fn strip_leading_zeroes(mut bytes: &[u8]) -> &[u8] {
57while let Some((byte, rest)) = bytes.split_first() {
58if *byte == 0 && !rest.is_empty() {
59 bytes = rest;
60 } else {
61break;
62 }
63 }
6465 bytes
66}
6768/// Does the given integer need a leading zero?
69fn needs_leading_zero(bytes: &[u8]) -> bool {
70matches!(bytes.get(0), Some(byte) if *byte >= 0x80)
71}