Skip to main content

dryoc/dryocstream/
tag.rs

1use std::fmt;
2use std::ops::{
3    BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not, Sub, SubAssign,
4};
5
6use crate::constants::{
7    CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_MESSAGE,
8    CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH,
9    CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY,
10};
11
12/// Message tag definitions.
13#[derive(Clone, Copy, PartialEq, Eq, Hash)]
14pub struct Tag(u8);
15
16const TAG_ITER_FLAGS: [Tag; 2] = [Tag::PUSH, Tag::REKEY];
17const TAG_ITER_NAMES: [(&str, Tag); 2] = [("PUSH", Tag::PUSH), ("REKEY", Tag::REKEY)];
18
19impl Tag {
20    /// Indicates the end of the stream.
21    pub const FINAL: Self = Self(Self::PUSH.bits() | Self::REKEY.bits());
22    const KNOWN_BITS: u8 = Self::MESSAGE.bits() | Self::PUSH.bits() | Self::REKEY.bits();
23    /// Describes a normal message in a stream.
24    pub const MESSAGE: Self = Self(CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_MESSAGE);
25    /// Indicates the message marks the end of a series of messages in a
26    /// stream, but not the end of the stream.
27    pub const PUSH: Self = Self(CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH);
28    /// Derives a new key for the stream.
29    pub const REKEY: Self = Self(CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY);
30
31    /// Get a flags value with all bits unset.
32    #[inline]
33    pub const fn empty() -> Self {
34        Self(0)
35    }
36
37    /// Get a flags value with all known bits set.
38    #[inline]
39    pub const fn all() -> Self {
40        Self(Self::KNOWN_BITS)
41    }
42
43    /// Get the underlying bits value.
44    #[inline]
45    pub const fn bits(&self) -> u8 {
46        self.0
47    }
48
49    /// Convert from a bits value, returning `None` if any unknown bits are set.
50    #[inline]
51    pub const fn from_bits(bits: u8) -> Option<Self> {
52        if bits & !Self::KNOWN_BITS == 0 {
53            Some(Self(bits))
54        } else {
55            None
56        }
57    }
58
59    /// Convert from a bits value, unsetting any unknown bits.
60    #[inline]
61    pub const fn from_bits_truncate(bits: u8) -> Self {
62        Self(bits & Self::KNOWN_BITS)
63    }
64
65    /// Convert from a bits value exactly.
66    ///
67    /// Values containing unknown bits are rejected when passed to
68    /// [`DryocStream::push`](super::DryocStream::push), and authenticated
69    /// unknown tags are rejected by Rustaceous pull streams.
70    #[inline]
71    pub const fn from_bits_retain(bits: u8) -> Self {
72        Self(bits)
73    }
74
75    /// Get a flags value with the bits of a flag with the given name set.
76    pub fn from_name(name: &str) -> Option<Self> {
77        match name {
78            "MESSAGE" => Some(Self::MESSAGE),
79            "PUSH" => Some(Self::PUSH),
80            "REKEY" => Some(Self::REKEY),
81            "FINAL" => Some(Self::FINAL),
82            _ => None,
83        }
84    }
85
86    /// Whether all bits in this flags value are unset.
87    #[inline]
88    pub const fn is_empty(&self) -> bool {
89        self.bits() == 0
90    }
91
92    /// Whether all known bits in this flags value are set.
93    #[inline]
94    pub const fn is_all(&self) -> bool {
95        Self::KNOWN_BITS | self.bits() == self.bits()
96    }
97
98    /// Whether any set bits in a source flags value are also set in a target
99    /// flags value.
100    #[inline]
101    pub const fn intersects(&self, other: Self) -> bool {
102        self.bits() & other.bits() != 0
103    }
104
105    /// Whether all set bits in a source flags value are also set in a target
106    /// flags value.
107    #[inline]
108    pub const fn contains(&self, other: Self) -> bool {
109        self.bits() & other.bits() == other.bits()
110    }
111
112    /// The bitwise or (`|`) of the bits in two flags values.
113    #[inline]
114    pub fn insert(&mut self, other: Self) {
115        *self = self.union(other);
116    }
117
118    /// The intersection of a source flags value with the complement of a target
119    /// flags value (`&!`).
120    #[inline]
121    pub fn remove(&mut self, other: Self) {
122        *self = self.difference(other);
123    }
124
125    /// The bitwise exclusive-or (`^`) of the bits in two flags values.
126    #[inline]
127    pub fn toggle(&mut self, other: Self) {
128        *self = self.symmetric_difference(other);
129    }
130
131    /// Call [`insert`](Self::insert) when `value` is `true` or
132    /// [`remove`](Self::remove) when `value` is `false`.
133    #[inline]
134    pub fn set(&mut self, other: Self, value: bool) {
135        if value {
136            self.insert(other);
137        } else {
138            self.remove(other);
139        }
140    }
141
142    /// Unsets all bits in the flags.
143    #[inline]
144    pub fn clear(&mut self) {
145        *self = Self::empty();
146    }
147
148    /// The bitwise and (`&`) of the bits in two flags values.
149    #[inline]
150    #[must_use]
151    pub const fn intersection(self, other: Self) -> Self {
152        Self(self.bits() & other.bits())
153    }
154
155    /// The bitwise or (`|`) of the bits in two flags values.
156    #[inline]
157    #[must_use]
158    pub const fn union(self, other: Self) -> Self {
159        Self(self.bits() | other.bits())
160    }
161
162    /// The intersection of a source flags value with the complement of a target
163    /// flags value (`&!`).
164    #[inline]
165    #[must_use]
166    pub const fn difference(self, other: Self) -> Self {
167        Self(self.bits() & !other.bits())
168    }
169
170    /// The bitwise exclusive-or (`^`) of the bits in two flags values.
171    #[inline]
172    #[must_use]
173    pub const fn symmetric_difference(self, other: Self) -> Self {
174        Self(self.bits() ^ other.bits())
175    }
176
177    /// The bitwise negation (`!`) of the bits in a flags value, truncating the
178    /// result.
179    #[inline]
180    #[must_use]
181    pub const fn complement(self) -> Self {
182        Self::from_bits_truncate(!self.bits())
183    }
184
185    /// Yield a set of contained flags values.
186    pub const fn iter(&self) -> TagIter {
187        TagIter {
188            remaining: *self,
189            index: 0,
190            yielded_unknown: false,
191        }
192    }
193
194    /// Yield a set of contained named flags values.
195    pub const fn iter_names(&self) -> TagIterNames {
196        TagIterNames {
197            remaining: *self,
198            index: 0,
199        }
200    }
201}
202
203impl Default for Tag {
204    fn default() -> Self {
205        Self::empty()
206    }
207}
208
209impl fmt::Debug for Tag {
210    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211        f.write_str("Tag(")?;
212
213        let mut first = true;
214        for (name, _) in self.iter_names() {
215            if !first {
216                f.write_str(" | ")?;
217            }
218            first = false;
219            f.write_str(name)?;
220        }
221
222        let unknown = self.bits() & !Self::KNOWN_BITS;
223        if unknown != 0 || first {
224            if !first {
225                f.write_str(" | ")?;
226            }
227            write!(f, "0x{unknown:x}")?;
228        }
229
230        f.write_str(")")
231    }
232}
233
234impl fmt::Binary for Tag {
235    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
236        fmt::Binary::fmt(&self.bits(), f)
237    }
238}
239
240impl fmt::Octal for Tag {
241    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242        fmt::Octal::fmt(&self.bits(), f)
243    }
244}
245
246impl fmt::LowerHex for Tag {
247    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248        fmt::LowerHex::fmt(&self.bits(), f)
249    }
250}
251
252impl fmt::UpperHex for Tag {
253    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
254        fmt::UpperHex::fmt(&self.bits(), f)
255    }
256}
257
258impl BitOr for Tag {
259    type Output = Self;
260
261    #[inline]
262    fn bitor(self, other: Self) -> Self {
263        self.union(other)
264    }
265}
266
267impl BitOrAssign for Tag {
268    #[inline]
269    fn bitor_assign(&mut self, other: Self) {
270        self.insert(other);
271    }
272}
273
274impl BitAnd for Tag {
275    type Output = Self;
276
277    #[inline]
278    fn bitand(self, other: Self) -> Self {
279        self.intersection(other)
280    }
281}
282
283impl BitAndAssign for Tag {
284    #[inline]
285    fn bitand_assign(&mut self, other: Self) {
286        *self = self.intersection(other);
287    }
288}
289
290impl BitXor for Tag {
291    type Output = Self;
292
293    #[inline]
294    fn bitxor(self, other: Self) -> Self {
295        self.symmetric_difference(other)
296    }
297}
298
299impl BitXorAssign for Tag {
300    #[inline]
301    fn bitxor_assign(&mut self, other: Self) {
302        self.toggle(other);
303    }
304}
305
306impl Sub for Tag {
307    type Output = Self;
308
309    #[inline]
310    fn sub(self, other: Self) -> Self {
311        self.difference(other)
312    }
313}
314
315impl SubAssign for Tag {
316    #[inline]
317    fn sub_assign(&mut self, other: Self) {
318        self.remove(other);
319    }
320}
321
322impl Not for Tag {
323    type Output = Self;
324
325    #[inline]
326    fn not(self) -> Self {
327        self.complement()
328    }
329}
330
331impl Extend<Tag> for Tag {
332    fn extend<T: IntoIterator<Item = Self>>(&mut self, iter: T) {
333        for item in iter {
334            self.insert(item);
335        }
336    }
337}
338
339impl FromIterator<Tag> for Tag {
340    fn from_iter<T: IntoIterator<Item = Self>>(iter: T) -> Self {
341        let mut result = Self::empty();
342        result.extend(iter);
343        result
344    }
345}
346
347impl IntoIterator for Tag {
348    type IntoIter = TagIter;
349    type Item = Tag;
350
351    fn into_iter(self) -> Self::IntoIter {
352        self.iter()
353    }
354}
355
356impl TryFrom<u8> for Tag {
357    type Error = crate::Error;
358
359    fn try_from(other: u8) -> Result<Self, Self::Error> {
360        Self::from_bits(other).ok_or(crate::Error::InvalidValue {
361            context: crate::ErrorContext::Tag,
362            actual: other as u64,
363            constraint: crate::ValueConstraint::AllowedBits {
364                mask: Self::KNOWN_BITS as u64,
365            },
366        })
367    }
368}
369
370/// Iterator over contained secretstream tags.
371#[derive(Clone, Debug)]
372pub struct TagIter {
373    remaining: Tag,
374    index: usize,
375    yielded_unknown: bool,
376}
377
378impl Iterator for TagIter {
379    type Item = Tag;
380
381    fn next(&mut self) -> Option<Self::Item> {
382        while self.index < TAG_ITER_FLAGS.len() {
383            let flag = TAG_ITER_FLAGS[self.index];
384            self.index += 1;
385
386            if self.remaining.contains(flag) {
387                self.remaining.remove(flag);
388                return Some(flag);
389            }
390        }
391
392        let unknown = self.remaining.bits() & !Tag::KNOWN_BITS;
393        if unknown != 0 && !self.yielded_unknown {
394            self.yielded_unknown = true;
395            self.remaining.remove(Tag::from_bits_retain(unknown));
396            Some(Tag::from_bits_retain(unknown))
397        } else {
398            None
399        }
400    }
401}
402
403/// Iterator over contained named secretstream tags.
404#[derive(Clone, Debug)]
405pub struct TagIterNames {
406    remaining: Tag,
407    index: usize,
408}
409
410impl Iterator for TagIterNames {
411    type Item = (&'static str, Tag);
412
413    fn next(&mut self) -> Option<Self::Item> {
414        while self.index < TAG_ITER_NAMES.len() {
415            let (name, flag) = TAG_ITER_NAMES[self.index];
416            self.index += 1;
417
418            if self.remaining.contains(flag) {
419                self.remaining.remove(flag);
420                return Some((name, flag));
421            }
422        }
423
424        None
425    }
426}
427
428#[cfg(test)]
429mod tests {
430    use super::Tag;
431
432    #[test]
433    fn tag_constructors_and_names_cover_known_and_unknown_bits() {
434        assert_eq!(Tag::default(), Tag::empty());
435        assert_eq!(Tag::default(), Tag::MESSAGE);
436        assert_eq!(Tag::all(), Tag::FINAL);
437
438        for bits in 0..=u8::MAX {
439            let retained = Tag::from_bits_retain(bits);
440            assert_eq!(retained.bits(), bits);
441            assert_eq!(Tag::from_bits_truncate(bits).bits(), bits & Tag::KNOWN_BITS);
442
443            let expected = if bits & !Tag::KNOWN_BITS == 0 {
444                Some(retained)
445            } else {
446                None
447            };
448            assert_eq!(Tag::from_bits(bits), expected);
449        }
450
451        assert_eq!(
452            Tag::try_from(Tag::FINAL.bits()).expect("known tag bits should be accepted"),
453            Tag::FINAL
454        );
455        assert_eq!(Tag::from_name("MESSAGE"), Some(Tag::MESSAGE));
456        assert_eq!(Tag::from_name("PUSH"), Some(Tag::PUSH));
457        assert_eq!(Tag::from_name("REKEY"), Some(Tag::REKEY));
458        assert_eq!(Tag::from_name("FINAL"), Some(Tag::FINAL));
459        assert_eq!(Tag::from_name("UNKNOWN"), None);
460    }
461
462    #[test]
463    fn tag_from_u8_rejects_unknown_bits() {
464        let error = Tag::try_from(0x80).expect_err("unknown tag bits should be rejected");
465
466        assert!(matches!(
467            error,
468            crate::Error::InvalidValue {
469                context: crate::ErrorContext::Tag,
470                actual: 0x80,
471                constraint: crate::ValueConstraint::AllowedBits { .. },
472            }
473        ));
474    }
475
476    #[test]
477    fn tag_predicates_and_mutators_match_flag_semantics() {
478        assert!(Tag::empty().is_empty());
479        assert!(Tag::MESSAGE.is_empty());
480        assert!(!Tag::PUSH.is_empty());
481        assert!(Tag::FINAL.is_all());
482        assert!(Tag::from_bits_retain(Tag::FINAL.bits() | 0x80).is_all());
483        assert!(!Tag::PUSH.is_all());
484
485        assert!(Tag::FINAL.contains(Tag::PUSH));
486        assert!(Tag::PUSH.contains(Tag::MESSAGE));
487        assert!(!Tag::PUSH.contains(Tag::REKEY));
488        assert!(Tag::FINAL.intersects(Tag::PUSH));
489        assert!(!Tag::PUSH.intersects(Tag::REKEY));
490
491        let mut tag = Tag::empty();
492        tag.insert(Tag::PUSH);
493        assert_eq!(tag, Tag::PUSH);
494        tag.insert(Tag::REKEY);
495        assert_eq!(tag, Tag::FINAL);
496        tag.remove(Tag::PUSH);
497        assert_eq!(tag, Tag::REKEY);
498        tag.toggle(Tag::PUSH);
499        assert_eq!(tag, Tag::FINAL);
500        tag.set(Tag::REKEY, false);
501        assert_eq!(tag, Tag::PUSH);
502        tag.set(Tag::REKEY, true);
503        assert_eq!(tag, Tag::FINAL);
504        tag.clear();
505        assert_eq!(tag, Tag::empty());
506    }
507
508    #[test]
509    fn tag_set_operations_and_operators_match_flag_semantics() {
510        assert_eq!(Tag::PUSH.union(Tag::REKEY), Tag::FINAL);
511        assert_eq!(Tag::FINAL.intersection(Tag::PUSH), Tag::PUSH);
512        assert_eq!(Tag::FINAL.difference(Tag::PUSH), Tag::REKEY);
513        assert_eq!(Tag::FINAL.symmetric_difference(Tag::PUSH), Tag::REKEY);
514        assert_eq!(Tag::PUSH.complement(), Tag::REKEY);
515
516        assert_eq!(Tag::PUSH | Tag::REKEY, Tag::FINAL);
517        assert_eq!(Tag::FINAL & Tag::PUSH, Tag::PUSH);
518        assert_eq!(Tag::FINAL ^ Tag::PUSH, Tag::REKEY);
519        assert_eq!(Tag::FINAL - Tag::PUSH, Tag::REKEY);
520        assert_eq!(!Tag::PUSH, Tag::REKEY);
521
522        let mut tag = Tag::PUSH;
523        tag |= Tag::REKEY;
524        assert_eq!(tag, Tag::FINAL);
525        tag &= Tag::PUSH;
526        assert_eq!(tag, Tag::PUSH);
527        tag ^= Tag::REKEY;
528        assert_eq!(tag, Tag::FINAL);
529        tag -= Tag::PUSH;
530        assert_eq!(tag, Tag::REKEY);
531    }
532
533    #[test]
534    fn tag_iterators_skip_zero_bit_message_and_retain_unknown_bits() {
535        assert_eq!(Tag::MESSAGE.iter().collect::<Vec<_>>(), Vec::<Tag>::new());
536        assert_eq!(
537            Tag::FINAL.iter().collect::<Vec<_>>(),
538            vec![Tag::PUSH, Tag::REKEY]
539        );
540        assert_eq!(
541            Tag::FINAL.iter_names().collect::<Vec<_>>(),
542            vec![("PUSH", Tag::PUSH), ("REKEY", Tag::REKEY)]
543        );
544
545        let unknown = Tag::from_bits_retain(0x80);
546        let retained = Tag::from_bits_retain(Tag::FINAL.bits() | unknown.bits());
547
548        assert_eq!(
549            retained.iter().collect::<Vec<_>>(),
550            vec![Tag::PUSH, Tag::REKEY, unknown]
551        );
552        assert_eq!(
553            retained.iter_names().collect::<Vec<_>>(),
554            vec![("PUSH", Tag::PUSH), ("REKEY", Tag::REKEY)]
555        );
556        assert_eq!(unknown.iter().collect::<Vec<_>>(), vec![unknown]);
557        assert_eq!(unknown.iter_names().collect::<Vec<_>>(), Vec::new());
558        assert_eq!(
559            Tag::FINAL.into_iter().collect::<Vec<_>>(),
560            vec![Tag::PUSH, Tag::REKEY]
561        );
562    }
563
564    #[test]
565    fn tag_formatting_matches_bitflags_style() {
566        assert_eq!(format!("{:?}", Tag::empty()), "Tag(0x0)");
567        assert_eq!(format!("{:?}", Tag::MESSAGE), "Tag(0x0)");
568        assert_eq!(format!("{:?}", Tag::PUSH), "Tag(PUSH)");
569        assert_eq!(format!("{:?}", Tag::REKEY), "Tag(REKEY)");
570        assert_eq!(format!("{:?}", Tag::FINAL), "Tag(PUSH | REKEY)");
571
572        let retained = Tag::from_bits_retain(Tag::FINAL.bits() | 0x80);
573        assert_eq!(format!("{retained:?}"), "Tag(PUSH | REKEY | 0x80)");
574        assert_eq!(format!("{retained:b}"), format!("{:b}", retained.bits()));
575        assert_eq!(format!("{retained:o}"), format!("{:o}", retained.bits()));
576        assert_eq!(format!("{retained:x}"), format!("{:x}", retained.bits()));
577        assert_eq!(format!("{retained:X}"), format!("{:X}", retained.bits()));
578        assert_eq!(
579            format!("{retained:#04x}"),
580            format!("{:#04x}", retained.bits())
581        );
582    }
583
584    #[test]
585    fn tag_collection_traits_accumulate_flags() {
586        let mut tag = Tag::empty();
587        tag.extend([Tag::PUSH, Tag::REKEY]);
588        assert_eq!(tag, Tag::FINAL);
589
590        let tag: Tag = [Tag::PUSH, Tag::REKEY].into_iter().collect();
591        assert_eq!(tag, Tag::FINAL);
592    }
593}