/rust/registry/src/index.crates.io-1949cf8c6b5b557f/const-oid-0.10.2/src/encoder.rs
Line | Count | Source |
1 | | //! OID encoder with `const` support. |
2 | | |
3 | | use crate::{ |
4 | | Arc, Buffer, Error, ObjectIdentifier, Result, |
5 | | arcs::{ARC_MAX_FIRST, ARC_MAX_SECOND}, |
6 | | }; |
7 | | |
8 | | /// BER/DER encoder. |
9 | | #[derive(Debug)] |
10 | | pub(crate) struct Encoder<const MAX_SIZE: usize> { |
11 | | /// Current state. |
12 | | state: State, |
13 | | |
14 | | /// Bytes of the OID being BER-encoded in-progress. |
15 | | bytes: [u8; MAX_SIZE], |
16 | | |
17 | | /// Current position within the byte buffer. |
18 | | cursor: usize, |
19 | | } |
20 | | |
21 | | /// Current state of the encoder. |
22 | | #[derive(Debug)] |
23 | | enum State { |
24 | | /// Initial state - no arcs yet encoded. |
25 | | Initial, |
26 | | |
27 | | /// First arc has been supplied and stored as the wrapped [`Arc`]. |
28 | | FirstArc(Arc), |
29 | | |
30 | | /// Encoding base 128 body of the OID. |
31 | | Body, |
32 | | } |
33 | | |
34 | | impl<const MAX_SIZE: usize> Encoder<MAX_SIZE> { |
35 | | /// Create a new encoder initialized to an empty default state. |
36 | 0 | pub(crate) const fn new() -> Self { |
37 | 0 | Self { |
38 | 0 | state: State::Initial, |
39 | 0 | bytes: [0u8; MAX_SIZE], |
40 | 0 | cursor: 0, |
41 | 0 | } |
42 | 0 | } |
43 | | |
44 | | /// Extend an existing OID. |
45 | 0 | pub(crate) const fn extend(oid: ObjectIdentifier<MAX_SIZE>) -> Self { |
46 | 0 | Self { |
47 | 0 | state: State::Body, |
48 | 0 | bytes: oid.ber.bytes, |
49 | 0 | cursor: oid.ber.length as usize, |
50 | 0 | } |
51 | 0 | } |
52 | | |
53 | | /// Encode an [`Arc`] as base 128 into the internal buffer. |
54 | 0 | pub(crate) const fn arc(mut self, arc: Arc) -> Result<Self> { |
55 | 0 | match self.state { |
56 | | State::Initial => { |
57 | 0 | if arc > ARC_MAX_FIRST { |
58 | 0 | return Err(Error::ArcInvalid { arc }); |
59 | 0 | } |
60 | | |
61 | 0 | self.state = State::FirstArc(arc); |
62 | 0 | Ok(self) |
63 | | } |
64 | 0 | State::FirstArc(first_arc) => { |
65 | 0 | if arc > ARC_MAX_SECOND { |
66 | 0 | return Err(Error::ArcInvalid { arc }); |
67 | 0 | } |
68 | | |
69 | 0 | self.state = State::Body; |
70 | 0 | self.bytes[0] = checked_add!( |
71 | 0 | checked_mul!(checked_add!(ARC_MAX_SECOND, 1), first_arc), |
72 | 0 | arc |
73 | | ) as u8; |
74 | 0 | self.cursor = 1; |
75 | 0 | Ok(self) |
76 | | } |
77 | 0 | State::Body => self.encode_base128(arc), |
78 | | } |
79 | 0 | } |
80 | | |
81 | | /// Finish encoding an OID. |
82 | 0 | pub(crate) const fn finish(self) -> Result<ObjectIdentifier<MAX_SIZE>> { |
83 | 0 | if self.cursor == 0 { |
84 | 0 | return Err(Error::Empty); |
85 | 0 | } |
86 | | |
87 | 0 | let ber = Buffer { |
88 | 0 | bytes: self.bytes, |
89 | 0 | length: self.cursor as u8, |
90 | 0 | }; |
91 | | |
92 | 0 | Ok(ObjectIdentifier { ber }) |
93 | 0 | } |
94 | | |
95 | | /// Encode base 128. |
96 | 0 | const fn encode_base128(mut self, arc: Arc) -> Result<Self> { |
97 | 0 | let nbytes = base128_len(arc); |
98 | 0 | let end_pos = checked_add!(self.cursor, nbytes); |
99 | | |
100 | 0 | if end_pos > MAX_SIZE { |
101 | 0 | return Err(Error::Length); |
102 | 0 | } |
103 | | |
104 | 0 | let mut i = 0; |
105 | 0 | while i < nbytes { |
106 | | // TODO(tarcieri): use `?` when stable in `const fn` |
107 | 0 | self.bytes[self.cursor] = match base128_byte(arc, i, nbytes) { |
108 | 0 | Ok(byte) => byte, |
109 | 0 | Err(e) => return Err(e), |
110 | | }; |
111 | 0 | self.cursor = checked_add!(self.cursor, 1); |
112 | 0 | i = checked_add!(i, 1); |
113 | | } |
114 | | |
115 | 0 | Ok(self) |
116 | 0 | } |
117 | | } |
118 | | |
119 | | /// Compute the length of an arc when encoded in base 128. |
120 | 0 | const fn base128_len(arc: Arc) -> usize { |
121 | 0 | match arc { |
122 | 0 | 0..=0x7f => 1, // up to 7 bits |
123 | 0 | 0x80..=0x3fff => 2, // up to 14 bits |
124 | 0 | 0x4000..=0x1fffff => 3, // up to 21 bits |
125 | 0 | 0x200000..=0x0fffffff => 4, // up to 28 bits |
126 | 0 | _ => 5, |
127 | | } |
128 | 0 | } |
129 | | |
130 | | /// Compute the big endian base 128 encoding of the given [`Arc`] at the given byte. |
131 | 0 | const fn base128_byte(arc: Arc, pos: usize, total: usize) -> Result<u8> { |
132 | 0 | debug_assert!(pos < total); |
133 | 0 | let last_byte = checked_add!(pos, 1) == total; |
134 | 0 | let mask = if last_byte { 0 } else { 0b10000000 }; |
135 | 0 | let shift = checked_mul!(checked_sub!(checked_sub!(total, pos), 1), 7); |
136 | 0 | Ok(((arc >> shift) & 0b1111111) as u8 | mask) |
137 | 0 | } |
138 | | |
139 | | #[cfg(test)] |
140 | | #[allow(clippy::unwrap_used)] |
141 | | mod tests { |
142 | | use super::Encoder; |
143 | | use hex_literal::hex; |
144 | | |
145 | | /// OID `1.2.840.10045.2.1` encoded as ASN.1 BER/DER |
146 | | const EXAMPLE_OID_BER: &[u8] = &hex!("2A8648CE3D0201"); |
147 | | |
148 | | #[test] |
149 | | fn base128_byte() { |
150 | | let example_arc = 0x44332211; |
151 | | assert_eq!(super::base128_len(example_arc), 5); |
152 | | assert_eq!(super::base128_byte(example_arc, 0, 5).unwrap(), 0b10000100); |
153 | | assert_eq!(super::base128_byte(example_arc, 1, 5).unwrap(), 0b10100001); |
154 | | assert_eq!(super::base128_byte(example_arc, 2, 5).unwrap(), 0b11001100); |
155 | | assert_eq!(super::base128_byte(example_arc, 3, 5).unwrap(), 0b11000100); |
156 | | assert_eq!(super::base128_byte(example_arc, 4, 5).unwrap(), 0b10001); |
157 | | } |
158 | | |
159 | | #[test] |
160 | | fn encode() { |
161 | | let encoder = Encoder::<7>::new(); |
162 | | let encoder = encoder.arc(1).unwrap(); |
163 | | let encoder = encoder.arc(2).unwrap(); |
164 | | let encoder = encoder.arc(840).unwrap(); |
165 | | let encoder = encoder.arc(10045).unwrap(); |
166 | | let encoder = encoder.arc(2).unwrap(); |
167 | | let encoder = encoder.arc(1).unwrap(); |
168 | | assert_eq!(&encoder.bytes[..encoder.cursor], EXAMPLE_OID_BER); |
169 | | } |
170 | | } |