1use crate::bitstream::{BitReader, BitWriter, re_emit_bits};
5use crate::error::Error;
6use crate::origin_path::OriginPath;
7use crate::use_site_path::UseSitePath;
8use crate::varint::{read_varint, write_varint};
9
10pub const TLV_USE_SITE_PATH_OVERRIDES: u8 = 0x00;
12pub const TLV_FINGERPRINTS: u8 = 0x01;
14pub const TLV_PUBKEYS: u8 = 0x02;
17pub const TLV_ORIGIN_PATH_OVERRIDES: u8 = 0x03;
20
21#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct TlvSection {
25 pub use_site_path_overrides: Option<Vec<(u8, UseSitePath)>>,
27 pub fingerprints: Option<Vec<(u8, [u8; 4])>>,
29 pub pubkeys: Option<Vec<(u8, [u8; 65])>>,
33 pub origin_path_overrides: Option<Vec<(u8, OriginPath)>>,
36 pub unknown: Vec<(u8, Vec<u8>, usize)>,
39}
40
41impl TlvSection {
42 pub fn new_empty() -> Self {
44 Self {
48 use_site_path_overrides: None,
49 fingerprints: None,
50 pubkeys: None,
51 origin_path_overrides: None,
52 unknown: Vec::new(),
53 }
54 }
55
56 pub fn is_empty(&self) -> bool {
58 let Self {
61 use_site_path_overrides,
62 fingerprints,
63 pubkeys,
64 origin_path_overrides,
65 unknown,
66 } = self;
67 use_site_path_overrides.is_none()
68 && fingerprints.is_none()
69 && pubkeys.is_none()
70 && origin_path_overrides.is_none()
71 && unknown.is_empty()
72 }
73
74 pub fn write(&self, w: &mut BitWriter, key_index_width: u8) -> Result<(), Error> {
87 let Self {
89 use_site_path_overrides,
90 fingerprints,
91 pubkeys,
92 origin_path_overrides,
93 unknown,
94 } = self;
95
96 let mut entries: Vec<(u8, Vec<u8>, usize)> = Vec::new();
98
99 if let Some(overrides) = use_site_path_overrides {
100 if overrides.is_empty() {
101 return Err(Error::EmptyTlvEntry {
102 tag: TLV_USE_SITE_PATH_OVERRIDES,
103 });
104 }
105 let mut sub = BitWriter::new();
106 let mut last_idx: Option<u8> = None;
107 for (idx, path) in overrides {
108 if let Some(prev) = last_idx {
109 if *idx <= prev {
110 return Err(Error::OverrideOrderViolation {
111 prev,
112 current: *idx,
113 });
114 }
115 }
116 last_idx = Some(*idx);
117 sub.write_bits(u64::from(*idx), key_index_width as usize);
118 path.write(&mut sub)?;
119 }
120 let bit_len = sub.bit_len();
121 entries.push((TLV_USE_SITE_PATH_OVERRIDES, sub.into_bytes(), bit_len));
122 }
123 if let Some(fps) = fingerprints {
124 if fps.is_empty() {
125 return Err(Error::EmptyTlvEntry {
126 tag: TLV_FINGERPRINTS,
127 });
128 }
129 let mut sub = BitWriter::new();
130 let mut last_idx: Option<u8> = None;
131 for (idx, fp) in fps {
132 if let Some(prev) = last_idx {
133 if *idx <= prev {
134 return Err(Error::OverrideOrderViolation {
135 prev,
136 current: *idx,
137 });
138 }
139 }
140 last_idx = Some(*idx);
141 sub.write_bits(u64::from(*idx), key_index_width as usize);
142 for b in fp {
143 sub.write_bits(u64::from(*b), 8);
144 }
145 }
146 let bit_len = sub.bit_len();
147 entries.push((TLV_FINGERPRINTS, sub.into_bytes(), bit_len));
148 }
149 if let Some(pks) = pubkeys {
150 if pks.is_empty() {
151 return Err(Error::EmptyTlvEntry { tag: TLV_PUBKEYS });
152 }
153 let mut sub = BitWriter::new();
154 let mut last_idx: Option<u8> = None;
155 for (idx, xpub) in pks {
156 if let Some(prev) = last_idx {
157 if *idx <= prev {
158 return Err(Error::OverrideOrderViolation {
159 prev,
160 current: *idx,
161 });
162 }
163 }
164 last_idx = Some(*idx);
165 sub.write_bits(u64::from(*idx), key_index_width as usize);
166 for b in xpub {
167 sub.write_bits(u64::from(*b), 8);
168 }
169 }
170 let bit_len = sub.bit_len();
171 entries.push((TLV_PUBKEYS, sub.into_bytes(), bit_len));
172 }
173 if let Some(paths) = origin_path_overrides {
174 if paths.is_empty() {
175 return Err(Error::EmptyTlvEntry {
176 tag: TLV_ORIGIN_PATH_OVERRIDES,
177 });
178 }
179 let mut sub = BitWriter::new();
180 let mut last_idx: Option<u8> = None;
181 for (idx, path) in paths {
182 if let Some(prev) = last_idx {
183 if *idx <= prev {
184 return Err(Error::OverrideOrderViolation {
185 prev,
186 current: *idx,
187 });
188 }
189 }
190 last_idx = Some(*idx);
191 sub.write_bits(u64::from(*idx), key_index_width as usize);
192 path.write(&mut sub)?;
193 }
194 let bit_len = sub.bit_len();
195 entries.push((TLV_ORIGIN_PATH_OVERRIDES, sub.into_bytes(), bit_len));
196 }
197 for (tag, payload, bit_len) in unknown {
198 entries.push((*tag, payload.clone(), *bit_len));
199 }
200 entries.sort_by_key(|(t, _, _)| *t);
201
202 for (tag, payload, bit_len) in entries {
203 w.write_bits(u64::from(tag), 5);
204 write_varint(w, bit_len as u32)?;
205 re_emit_bits(w, &payload, bit_len)?;
206 }
207 Ok(())
208 }
209
210 pub fn read(r: &mut BitReader, key_index_width: u8, n: u8) -> Result<Self, Error> {
213 let mut section = Self::new_empty();
214 let mut last_tag: Option<u8> = None;
215 loop {
216 let entry_start = r.save_position();
219 if r.remaining_bits() < 5 {
220 reject_non_zero_pad(r)?;
225 break; }
227 let parse_result: Result<(), Error> = (|| {
234 let tag = r.read_bits(5)? as u8;
235 if let Some(prev) = last_tag {
239 if tag <= prev {
240 return Err(Error::TlvOrderingViolation { prev, current: tag });
241 }
242 }
243 let bit_len = read_varint(r)? as usize;
244 if bit_len > r.remaining_bits() {
245 return Err(Error::TlvLengthExceedsRemaining {
246 length: bit_len,
247 remaining: r.remaining_bits(),
248 });
249 }
250 if bit_len == 0 {
254 return Err(Error::EmptyTlvEntry { tag });
255 }
256 match tag {
257 TLV_USE_SITE_PATH_OVERRIDES => {
258 let entry = read_use_site_overrides(r, bit_len, key_index_width, n)?;
259 section.use_site_path_overrides = Some(entry);
260 }
261 TLV_FINGERPRINTS => {
262 let entry = read_fingerprints(r, bit_len, key_index_width, n)?;
263 section.fingerprints = Some(entry);
264 }
265 TLV_PUBKEYS => {
266 let entry = read_pubkeys(r, bit_len, key_index_width, n)?;
267 section.pubkeys = Some(entry);
268 }
269 TLV_ORIGIN_PATH_OVERRIDES => {
270 let entry = read_origin_path_overrides(r, bit_len, key_index_width, n)?;
271 section.origin_path_overrides = Some(entry);
272 }
273 _ => {
274 let mut sub = BitWriter::new();
276 let mut remaining = bit_len;
277 while remaining > 0 {
278 let chunk = remaining.min(8);
279 let bits = r.read_bits(chunk)?;
280 sub.write_bits(bits, chunk);
281 remaining -= chunk;
282 }
283 let payload = sub.into_bytes();
284 section.unknown.push((tag, payload, bit_len));
285 }
286 }
287 last_tag = Some(tag);
288 Ok(())
289 })();
290
291 match parse_result {
292 Ok(()) => continue,
293 Err(e) => {
294 r.restore_position(entry_start);
298 let remaining_at_entry_start = r.remaining_bits();
299 if remaining_at_entry_start <= 7 {
302 reject_non_zero_pad(r)?;
305 break;
306 }
307 return Err(e);
310 }
311 }
312 }
313 Ok(section)
314 }
315}
316
317fn reject_non_zero_pad(r: &mut BitReader) -> Result<(), Error> {
325 let bits = r.remaining_bits();
326 if bits == 0 {
327 return Ok(());
328 }
329 debug_assert!(bits <= 7, "pad-tolerance band is ≤7 bits");
330 let saved = r.save_position();
331 let pad = r.read_bits(bits)?;
332 r.restore_position(saved);
333 if pad != 0 {
334 return Err(Error::MalformedPayloadPadding { bits });
335 }
336 Ok(())
337}
338
339fn read_sparse_tlv_idx(
348 r: &mut BitReader,
349 key_index_width: u8,
350 n: u8,
351 last_idx: Option<u8>,
352) -> Result<u8, Error> {
353 let idx = r.read_bits(key_index_width as usize)? as u8;
354 if idx >= n {
355 return Err(Error::PlaceholderIndexOutOfRange { idx, n });
356 }
357 if let Some(prev) = last_idx {
358 if idx <= prev {
359 return Err(Error::OverrideOrderViolation { prev, current: idx });
360 }
361 }
362 Ok(idx)
363}
364
365fn read_sparse_tlv_body<T, F>(
379 r: &mut BitReader,
380 bit_len: usize,
381 tag: u8,
382 key_index_width: u8,
383 n: u8,
384 mut read_value: F,
385) -> Result<Vec<(u8, T)>, Error>
386where
387 F: FnMut(&mut BitReader) -> Result<T, Error>,
388{
389 let start = r.bit_position();
390 let saved_limit = r.save_bit_limit();
391 r.set_bit_limit_for_scope(start + bit_len);
392
393 let mut entries: Vec<(u8, T)> = Vec::new();
394 let mut last_idx: Option<u8> = None;
395
396 let result = (|| -> Result<(), Error> {
397 while r.bit_position() - start < bit_len {
398 let idx = read_sparse_tlv_idx(r, key_index_width, n, last_idx)?;
399 let value = read_value(r)?;
400 last_idx = Some(idx);
401 entries.push((idx, value));
402 }
403 Ok(())
404 })();
405
406 r.restore_bit_limit(saved_limit);
407 result?;
408
409 if entries.is_empty() {
410 return Err(Error::EmptyTlvEntry { tag });
411 }
412 Ok(entries)
413}
414
415fn read_use_site_overrides(
416 r: &mut BitReader,
417 bit_len: usize,
418 key_index_width: u8,
419 n: u8,
420) -> Result<Vec<(u8, UseSitePath)>, Error> {
421 read_sparse_tlv_body(
422 r,
423 bit_len,
424 TLV_USE_SITE_PATH_OVERRIDES,
425 key_index_width,
426 n,
427 UseSitePath::read,
428 )
429}
430
431fn read_fingerprints(
432 r: &mut BitReader,
433 bit_len: usize,
434 key_index_width: u8,
435 n: u8,
436) -> Result<Vec<(u8, [u8; 4])>, Error> {
437 read_sparse_tlv_body(r, bit_len, TLV_FINGERPRINTS, key_index_width, n, |r| {
438 let mut fp = [0u8; 4];
439 for byte in &mut fp {
440 *byte = r.read_bits(8)? as u8;
441 }
442 Ok(fp)
443 })
444}
445
446fn read_pubkeys(
447 r: &mut BitReader,
448 bit_len: usize,
449 key_index_width: u8,
450 n: u8,
451) -> Result<Vec<(u8, [u8; 65])>, Error> {
452 read_sparse_tlv_body(r, bit_len, TLV_PUBKEYS, key_index_width, n, |r| {
453 let mut xpub = [0u8; 65];
454 for byte in &mut xpub {
455 *byte = r.read_bits(8)? as u8;
456 }
457 Ok(xpub)
458 })
459}
460
461fn read_origin_path_overrides(
462 r: &mut BitReader,
463 bit_len: usize,
464 key_index_width: u8,
465 n: u8,
466) -> Result<Vec<(u8, OriginPath)>, Error> {
467 read_sparse_tlv_body(
470 r,
471 bit_len,
472 TLV_ORIGIN_PATH_OVERRIDES,
473 key_index_width,
474 n,
475 OriginPath::read,
476 )
477}
478
479#[cfg(test)]
480mod tests {
481 use super::*;
482 use crate::origin_path::PathComponent;
483
484 #[test]
485 fn empty_tlv_section_round_trip() {
486 let s = TlvSection::new_empty();
487 assert!(s.is_empty());
488 let mut w = BitWriter::new();
489 s.write(&mut w, 2).unwrap();
490 assert_eq!(w.bit_len(), 0);
491 }
492
493 #[test]
494 fn use_site_path_override_round_trip() {
495 let mut s = TlvSection::new_empty();
496 s.use_site_path_overrides = Some(vec![(
497 1u8,
498 UseSitePath {
499 multipath: None,
500 wildcard_hardened: true,
501 },
502 )]);
503 let mut w = BitWriter::new();
504 s.write(&mut w, 2).unwrap();
505 let bit_len = w.bit_len();
506 let bytes = w.into_bytes();
507 let mut r = BitReader::new(&bytes);
508 let s2 = TlvSection::read(&mut r, 2, 3).unwrap();
509 assert_eq!(s2, s);
510 assert_eq!(r.bit_position(), bit_len);
511 }
512
513 #[test]
514 fn fingerprint_round_trip() {
515 let mut s = TlvSection::new_empty();
516 s.fingerprints = Some(vec![
517 (0u8, [0xaa, 0xbb, 0xcc, 0xdd]),
518 (2u8, [0x11, 0x22, 0x33, 0x44]),
519 ]);
520 let mut w = BitWriter::new();
521 s.write(&mut w, 2).unwrap();
522 let bytes = w.into_bytes();
523 let mut r = BitReader::new(&bytes);
524 let s2 = TlvSection::read(&mut r, 2, 3).unwrap();
525 assert_eq!(s2, s);
526 }
527
528 #[test]
529 fn pubkeys_round_trip() {
530 let mut xpub_a = [0u8; 65];
532 for (i, b) in xpub_a.iter_mut().enumerate() {
533 *b = i as u8;
534 }
535 let mut xpub_b = [0u8; 65];
536 for (i, b) in xpub_b.iter_mut().enumerate() {
537 *b = (0xff - i as u8) ^ 0x5a;
538 }
539 let mut s = TlvSection::new_empty();
540 s.pubkeys = Some(vec![(0u8, xpub_a), (2u8, xpub_b)]);
541
542 let mut w = BitWriter::new();
543 s.write(&mut w, 2).unwrap();
544 let bit_len = w.bit_len();
545 let bytes = w.into_bytes();
546 let mut r = BitReader::new(&bytes);
547 let s2 = TlvSection::read(&mut r, 2, 3).unwrap();
548 assert_eq!(s2, s);
549 assert_eq!(r.bit_position(), bit_len);
550 }
551
552 #[test]
553 fn origin_path_overrides_round_trip() {
554 let bip84 = OriginPath {
556 components: vec![
557 PathComponent {
558 hardened: true,
559 value: 84,
560 },
561 PathComponent {
562 hardened: true,
563 value: 0,
564 },
565 PathComponent {
566 hardened: true,
567 value: 5,
568 },
569 ],
570 };
571 let bip48 = OriginPath {
572 components: vec![
573 PathComponent {
574 hardened: true,
575 value: 48,
576 },
577 PathComponent {
578 hardened: true,
579 value: 0,
580 },
581 PathComponent {
582 hardened: true,
583 value: 0,
584 },
585 PathComponent {
586 hardened: true,
587 value: 2,
588 },
589 ],
590 };
591 let mut s = TlvSection::new_empty();
592 s.origin_path_overrides = Some(vec![(0u8, bip84), (1u8, bip48)]);
593
594 let mut w = BitWriter::new();
595 s.write(&mut w, 2).unwrap();
596 let bit_len = w.bit_len();
597 let bytes = w.into_bytes();
598 let mut r = BitReader::new(&bytes);
599 let s2 = TlvSection::read(&mut r, 2, 3).unwrap();
600 assert_eq!(s2, s);
601 assert_eq!(r.bit_position(), bit_len);
602 }
603
604 #[test]
605 fn ascending_tag_order_enforced_in_encoder() {
606 let mut s = TlvSection::new_empty();
608 s.use_site_path_overrides = Some(vec![(
609 0,
610 UseSitePath {
611 multipath: None,
612 wildcard_hardened: false,
613 },
614 )]);
615 s.fingerprints = Some(vec![(0, [0u8; 4])]);
616 s.pubkeys = Some(vec![(0, [0u8; 65])]);
617 s.origin_path_overrides = Some(vec![(
618 0,
619 OriginPath {
620 components: vec![PathComponent {
621 hardened: true,
622 value: 84,
623 }],
624 },
625 )]);
626 let mut w = BitWriter::new();
627 s.write(&mut w, 2).unwrap();
628 let bytes = w.into_bytes();
629 let first_tag = (bytes[0] >> 3) & 0x1F;
630 assert_eq!(first_tag, TLV_USE_SITE_PATH_OVERRIDES);
631 }
632
633 #[test]
634 fn pubkeys_ordering_violation_rejected_at_encoder() {
635 let mut s = TlvSection::new_empty();
637 s.pubkeys = Some(vec![(1u8, [0u8; 65]), (0u8, [0u8; 65])]);
638 let mut w = BitWriter::new();
639 let result = s.write(&mut w, 2);
640 assert!(matches!(
641 result,
642 Err(Error::OverrideOrderViolation {
643 prev: 1,
644 current: 0
645 })
646 ));
647 }
648
649 #[test]
650 fn pubkeys_ordering_violation_rejected_at_decoder() {
651 let mut sub = BitWriter::new();
655 sub.write_bits(1, 2);
657 for _ in 0..65 {
658 sub.write_bits(0, 8);
659 }
660 sub.write_bits(1, 2);
662 for _ in 0..65 {
663 sub.write_bits(0, 8);
664 }
665 let bit_len = sub.bit_len();
666 let payload_bytes = sub.into_bytes();
667
668 let mut w = BitWriter::new();
669 w.write_bits(u64::from(TLV_PUBKEYS), 5);
670 write_varint(&mut w, bit_len as u32).unwrap();
671 re_emit_bits(&mut w, &payload_bytes, bit_len).unwrap();
672 let total_bit_len = w.bit_len();
673 let bytes = w.into_bytes();
674
675 let mut r = BitReader::with_bit_limit(&bytes, total_bit_len);
676 let result = TlvSection::read(&mut r, 2, 3);
677 assert!(matches!(
678 result,
679 Err(Error::OverrideOrderViolation {
680 prev: 1,
681 current: 1
682 })
683 ));
684 }
685
686 #[test]
687 fn read_sparse_tlv_idx_out_of_range() {
688 let mut sub = BitWriter::new();
690 sub.write_bits(3, 2);
691 let bit_len = sub.bit_len();
692 let bytes = sub.into_bytes();
693 let mut r = BitReader::with_bit_limit(&bytes, bit_len);
694
695 let result = read_sparse_tlv_idx(&mut r, 2, 2, None);
696 assert!(matches!(
697 result,
698 Err(Error::PlaceholderIndexOutOfRange { idx: 3, n: 2 })
699 ));
700 }
701
702 #[test]
703 fn read_sparse_tlv_idx_non_ascending() {
704 let mut sub = BitWriter::new();
705 sub.write_bits(0, 2);
706 let bit_len = sub.bit_len();
707 let bytes = sub.into_bytes();
708 let mut r = BitReader::with_bit_limit(&bytes, bit_len);
709
710 let result = read_sparse_tlv_idx(&mut r, 2, 3, Some(1));
711 assert!(matches!(
712 result,
713 Err(Error::OverrideOrderViolation {
714 prev: 1,
715 current: 0
716 })
717 ));
718 }
719
720 #[test]
721 fn empty_pubkeys_vec_rejected_at_encoder() {
722 let mut s = TlvSection::new_empty();
723 s.pubkeys = Some(Vec::new());
724 let mut w = BitWriter::new();
725 let result = s.write(&mut w, 2);
726 assert!(matches!(
727 result,
728 Err(Error::EmptyTlvEntry { tag }) if tag == TLV_PUBKEYS
729 ));
730 }
731
732 #[test]
733 fn empty_origin_path_overrides_vec_rejected_at_encoder() {
734 let mut s = TlvSection::new_empty();
735 s.origin_path_overrides = Some(Vec::new());
736 let mut w = BitWriter::new();
737 let result = s.write(&mut w, 2);
738 assert!(matches!(
739 result,
740 Err(Error::EmptyTlvEntry { tag }) if tag == TLV_ORIGIN_PATH_OVERRIDES
741 ));
742 }
743
744 fn craft_inflated_tlv_wire(
749 tag: u8,
750 idx: u8,
751 idx_width: u8,
752 record_payload_bits: &[(u64, usize)],
753 slack_bits: usize,
754 ) -> (Vec<u8>, usize) {
755 let mut w = BitWriter::new();
756 w.write_bits(u64::from(tag), 5);
758 let actual_record_bits: usize =
760 (idx_width as usize) + record_payload_bits.iter().map(|(_, n)| n).sum::<usize>();
761 let declared_bit_len = actual_record_bits + slack_bits;
762 write_varint(&mut w, declared_bit_len as u32).unwrap();
763 w.write_bits(u64::from(idx), idx_width as usize);
765 for (val, bits) in record_payload_bits {
766 w.write_bits(*val, *bits);
767 }
768 for _ in 0..slack_bits {
770 w.write_bits(0, 1);
771 }
772 let bit_len = w.bit_len();
773 (w.into_bytes(), bit_len)
774 }
775
776 #[test]
788 fn fingerprints_with_trailing_slack_rejected() {
789 let (bytes, total_bits) =
790 craft_inflated_tlv_wire(TLV_FINGERPRINTS, 0, 1, &[(0xDEAD_BEEF, 32)], 4);
791 let mut r = BitReader::with_bit_limit(&bytes, total_bits);
792 let result = TlvSection::read(&mut r, 1, 1);
793 assert!(
794 result.is_err(),
795 "trailing slack must be rejected, got {:?}",
796 result
797 );
798 }
799
800 #[test]
801 fn pubkeys_with_trailing_slack_rejected() {
802 let payload: Vec<(u64, usize)> = (0..65).map(|_i| (0x42u64, 8)).collect();
803 let (bytes, total_bits) = craft_inflated_tlv_wire(TLV_PUBKEYS, 0, 1, &payload, 3);
804 let mut r = BitReader::with_bit_limit(&bytes, total_bits);
805 let result = TlvSection::read(&mut r, 1, 1);
806 assert!(
807 result.is_err(),
808 "trailing slack must be rejected, got {:?}",
809 result
810 );
811 }
812
813 #[test]
814 fn use_site_path_overrides_with_trailing_slack_rejected() {
815 let mut path_w = BitWriter::new();
816 UseSitePath::standard_multipath()
817 .write(&mut path_w)
818 .unwrap();
819 let path_bit_len = path_w.bit_len();
820 let path_bytes = path_w.into_bytes();
821 let mut path_record: Vec<(u64, usize)> = Vec::new();
822 let mut br = BitReader::new(&path_bytes);
823 let mut consumed = 0;
824 while consumed < path_bit_len {
825 let chunk = (path_bit_len - consumed).min(8);
826 path_record.push((br.read_bits(chunk).unwrap(), chunk));
827 consumed += chunk;
828 }
829 let (bytes, total_bits) =
830 craft_inflated_tlv_wire(TLV_USE_SITE_PATH_OVERRIDES, 0, 1, &path_record, 2);
831 let mut r = BitReader::with_bit_limit(&bytes, total_bits);
832 let result = TlvSection::read(&mut r, 1, 1);
833 assert!(
834 result.is_err(),
835 "trailing slack must be rejected, got {:?}",
836 result
837 );
838 }
839
840 #[test]
841 fn origin_path_overrides_with_trailing_slack_rejected() {
842 let (bytes, total_bits) =
843 craft_inflated_tlv_wire(TLV_ORIGIN_PATH_OVERRIDES, 0, 1, &[(0, 4)], 5);
844 let mut r = BitReader::with_bit_limit(&bytes, total_bits);
845 let result = TlvSection::read(&mut r, 1, 1);
846 assert!(
847 result.is_err(),
848 "trailing slack must be rejected, got {:?}",
849 result
850 );
851 }
852
853 #[test]
859 fn non_zero_trailing_pad_under_5_bits_rejected() {
860 let mut w = BitWriter::new();
861 w.write_bits(0b101, 3); let total = w.bit_len();
863 let bytes = w.into_bytes();
864 let mut r = BitReader::with_bit_limit(&bytes, total);
865 let result = TlvSection::read(&mut r, 2, 3);
866 assert!(
867 matches!(result, Err(Error::MalformedPayloadPadding { bits: 3 })),
868 "expected MalformedPayloadPadding {{ bits: 3 }}, got {result:?}"
869 );
870 }
871
872 #[test]
876 fn non_zero_trailing_pad_5_to_7_bits_rejected() {
877 let mut w = BitWriter::new();
878 w.write_bits(0b100000, 6);
879 let total = w.bit_len();
880 let bytes = w.into_bytes();
881 let mut r = BitReader::with_bit_limit(&bytes, total);
882 let result = TlvSection::read(&mut r, 2, 3);
883 assert!(
884 matches!(result, Err(Error::MalformedPayloadPadding { bits: 6 })),
885 "expected MalformedPayloadPadding {{ bits: 6 }}, got {result:?}"
886 );
887 }
888
889 #[test]
892 fn zero_trailing_pad_accepted() {
893 for pad in 1..=7usize {
894 let mut w = BitWriter::new();
895 w.write_bits(0, pad);
896 let total = w.bit_len();
897 let bytes = w.into_bytes();
898 let mut r = BitReader::with_bit_limit(&bytes, total);
899 let result = TlvSection::read(&mut r, 2, 3);
900 assert!(
901 matches!(&result, Ok(s) if s.is_empty()),
902 "{pad}-bit zero pad must be accepted, got {result:?}"
903 );
904 }
905 }
906}