codec_cbor/
deterministic.rs1use std::fmt;
6use zeroize::{Zeroize, ZeroizeOnDrop};
7
8mod error;
9mod limits;
10
11pub use error::{DeterministicCborError, DeterministicCborProfileError};
12pub use limits::{
13 DETERMINISTIC_CBOR_NEGATIVE_MAX, DETERMINISTIC_CBOR_NEGATIVE_MIN,
14 MAX_DETERMINISTIC_CBOR_AGGREGATE_BYTE_STRING_BYTES,
15 MAX_DETERMINISTIC_CBOR_AGGREGATE_TEXT_BYTES, MAX_DETERMINISTIC_CBOR_CONTAINER_ENTRIES,
16 MAX_DETERMINISTIC_CBOR_INPUT_LEN, MAX_DETERMINISTIC_CBOR_NESTING_DEPTH,
17 MAX_DETERMINISTIC_CBOR_NODES, MAX_DETERMINISTIC_CBOR_OUTPUT_LEN,
18};
19
20#[non_exhaustive]
26pub enum DeterministicCborInteger {
27 Unsigned(u64),
29 Negative(DeterministicCborNegativeInteger),
31}
32
33impl DeterministicCborInteger {
34 pub const fn unsigned(value: u64) -> Self {
36 Self::Unsigned(value)
37 }
38
39 pub const fn negative(value: i64) -> Result<Self, DeterministicCborProfileError> {
44 if value < 0 {
45 Ok(Self::Negative(DeterministicCborNegativeInteger { value }))
46 } else {
47 Err(DeterministicCborProfileError::NegativeIntegerMustBeNegative)
48 }
49 }
50}
51
52impl fmt::Debug for DeterministicCborInteger {
53 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
54 match self {
55 Self::Unsigned(_) => formatter
56 .debug_tuple("DeterministicCborInteger::Unsigned")
57 .field(&Redacted)
58 .finish(),
59 Self::Negative(value) => formatter
60 .debug_tuple("DeterministicCborInteger::Negative")
61 .field(value)
62 .finish(),
63 }
64 }
65}
66
67impl DeterministicCborInteger {
68 fn zeroize_owned(&mut self) {
69 match self {
70 Self::Unsigned(value) => value.zeroize(),
71 Self::Negative(value) => value.zeroize_owned(),
72 }
73 }
74}
75
76impl Drop for DeterministicCborInteger {
77 fn drop(&mut self) {
78 self.zeroize_owned();
79 }
80}
81
82impl ZeroizeOnDrop for DeterministicCborInteger {}
83
84pub struct DeterministicCborNegativeInteger {
90 value: i64,
91}
92
93impl DeterministicCborNegativeInteger {
94 pub const fn value(&self) -> i64 {
96 self.value
97 }
98}
99
100impl fmt::Debug for DeterministicCborNegativeInteger {
101 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
102 formatter
103 .debug_tuple("DeterministicCborNegativeInteger")
104 .field(&Redacted)
105 .finish()
106 }
107}
108
109impl DeterministicCborNegativeInteger {
110 fn zeroize_owned(&mut self) {
111 self.value.zeroize();
112 }
113}
114
115impl Drop for DeterministicCborNegativeInteger {
116 fn drop(&mut self) {
117 self.zeroize_owned();
118 }
119}
120
121impl ZeroizeOnDrop for DeterministicCborNegativeInteger {}
122
123#[non_exhaustive]
129pub enum DeterministicCborMapKey {
130 Integer(DeterministicCborInteger),
132 Text(String),
134}
135
136impl DeterministicCborMapKey {
137 pub fn text(value: String) -> Self {
143 Self::Text(value)
144 }
145}
146
147impl fmt::Debug for DeterministicCborMapKey {
148 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
149 match self {
150 Self::Integer(value) => formatter
151 .debug_tuple("DeterministicCborMapKey::Integer")
152 .field(value)
153 .finish(),
154 Self::Text(value) => formatter
155 .debug_struct("DeterministicCborMapKey::Text")
156 .field("byte_len", &value.len())
157 .field("value", &Redacted)
158 .finish(),
159 }
160 }
161}
162
163impl Drop for DeterministicCborMapKey {
164 fn drop(&mut self) {
165 self.zeroize_owned();
166 }
167}
168
169impl DeterministicCborMapKey {
170 fn zeroize_owned(&mut self) {
171 match self {
172 Self::Integer(value) => value.zeroize_owned(),
173 Self::Text(value) => value.zeroize(),
174 }
175 }
176}
177
178impl ZeroizeOnDrop for DeterministicCborMapKey {}
179
180pub struct DeterministicCborMapEntry {
188 key: DeterministicCborMapKey,
189 value: DeterministicCborValue,
190}
191
192impl DeterministicCborMapEntry {
193 pub fn new(key: DeterministicCborMapKey, value: DeterministicCborValue) -> Self {
195 Self { key, value }
196 }
197
198 pub const fn key(&self) -> &DeterministicCborMapKey {
200 &self.key
201 }
202
203 pub const fn value(&self) -> &DeterministicCborValue {
205 &self.value
206 }
207}
208
209impl fmt::Debug for DeterministicCborMapEntry {
210 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
211 formatter
212 .debug_struct("DeterministicCborMapEntry")
213 .field("key", &self.key)
214 .field("value", &self.value)
215 .finish()
216 }
217}
218
219impl DeterministicCborMapEntry {
220 fn zeroize_owned(&mut self) {
221 self.key.zeroize_owned();
222 self.value.zeroize_owned();
223 }
224}
225
226impl Drop for DeterministicCborMapEntry {
227 fn drop(&mut self) {
228 self.zeroize_owned();
229 }
230}
231
232impl ZeroizeOnDrop for DeterministicCborMapEntry {}
233
234#[non_exhaustive]
246pub enum DeterministicCborValue {
247 Null,
249 Bool(bool),
251 Integer(DeterministicCborInteger),
253 Text(String),
255 Bytes(Vec<u8>),
257 Array(Vec<DeterministicCborValue>),
259 Map(Vec<DeterministicCborMapEntry>),
261}
262
263impl fmt::Debug for DeterministicCborValue {
264 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
265 match self {
266 Self::Null => formatter.write_str("DeterministicCborValue::Null"),
267 Self::Bool(_) => formatter
268 .debug_tuple("DeterministicCborValue::Bool")
269 .field(&Redacted)
270 .finish(),
271 Self::Integer(value) => formatter
272 .debug_tuple("DeterministicCborValue::Integer")
273 .field(value)
274 .finish(),
275 Self::Text(value) => formatter
276 .debug_struct("DeterministicCborValue::Text")
277 .field("byte_len", &value.len())
278 .field("value", &Redacted)
279 .finish(),
280 Self::Bytes(value) => formatter
281 .debug_struct("DeterministicCborValue::Bytes")
282 .field("byte_len", &value.len())
283 .field("value", &Redacted)
284 .finish(),
285 Self::Array(values) => formatter
286 .debug_struct("DeterministicCborValue::Array")
287 .field("len", &values.len())
288 .finish(),
289 Self::Map(entries) => formatter
290 .debug_struct("DeterministicCborValue::Map")
291 .field("len", &entries.len())
292 .finish(),
293 }
294 }
295}
296
297impl Drop for DeterministicCborValue {
298 fn drop(&mut self) {
299 self.zeroize_owned();
300 }
301}
302
303impl DeterministicCborValue {
304 fn zeroize_owned(&mut self) {
305 match self {
306 Self::Bool(value) => value.zeroize(),
307 Self::Integer(value) => value.zeroize_owned(),
308 Self::Text(value) => value.zeroize(),
309 Self::Bytes(value) => value.zeroize(),
310 Self::Array(values) => zeroize_values(values),
311 Self::Map(entries) => zeroize_entries(entries),
312 Self::Null => {}
313 }
314 }
315}
316
317impl ZeroizeOnDrop for DeterministicCborValue {}
318
319pub(crate) fn try_vec_with_capacity<T>(capacity: usize) -> Result<Vec<T>, DeterministicCborError> {
320 let mut values = Vec::new();
321 values
322 .try_reserve_exact(capacity)
323 .map_err(|_| DeterministicCborError::AllocationFailure)?;
324 Ok(values)
325}
326
327pub(crate) fn try_string_copy(value: &str) -> Result<String, DeterministicCborError> {
328 let mut copy = String::new();
329 copy.try_reserve_exact(value.len())
330 .map_err(|_| DeterministicCborError::AllocationFailure)?;
331 copy.push_str(value);
332 Ok(copy)
333}
334
335fn zeroize_values(values: &mut Vec<DeterministicCborValue>) {
336 for value in values.iter_mut() {
337 value.zeroize_owned();
338 }
339 values.clear();
340 values.spare_capacity_mut().zeroize();
341}
342
343fn zeroize_entries(entries: &mut Vec<DeterministicCborMapEntry>) {
344 for entry in entries.iter_mut() {
345 entry.zeroize_owned();
346 }
347 entries.clear();
348 entries.spare_capacity_mut().zeroize();
349}
350
351struct Redacted;
352
353impl fmt::Debug for Redacted {
354 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
355 formatter.write_str("<redacted>")
356 }
357}
358
359#[cfg(test)]
360mod tests;