1mod commit;
22pub mod encoding;
23pub mod hash;
24mod proof;
25mod tls;
26
27use std::{fmt, ops::Range};
28
29use rangeset::{Difference, IndexRanges, RangeSet, Union};
30use serde::{Deserialize, Serialize};
31
32use crate::connection::TranscriptLength;
33
34pub use commit::{
35 TranscriptCommitConfig, TranscriptCommitConfigBuilder, TranscriptCommitConfigBuilderError,
36 TranscriptCommitRequest, TranscriptCommitment, TranscriptCommitmentKind, TranscriptSecret,
37};
38pub use proof::{
39 TranscriptProof, TranscriptProofBuilder, TranscriptProofBuilderError, TranscriptProofError,
40};
41pub use tls::{Record, TlsTranscript};
42pub use tls_core::msgs::enums::ContentType;
43
44#[derive(Clone, Serialize, Deserialize)]
47pub struct Transcript {
48 sent: Vec<u8>,
50 received: Vec<u8>,
52}
53
54opaque_debug::implement!(Transcript);
55
56impl Transcript {
57 pub fn new(sent: impl Into<Vec<u8>>, received: impl Into<Vec<u8>>) -> Self {
59 Self {
60 sent: sent.into(),
61 received: received.into(),
62 }
63 }
64
65 pub fn sent(&self) -> &[u8] {
67 &self.sent
68 }
69
70 pub fn received(&self) -> &[u8] {
72 &self.received
73 }
74
75 #[allow(clippy::len_without_is_empty)]
77 pub fn len(&self) -> (usize, usize) {
78 (self.sent.len(), self.received.len())
79 }
80
81 pub(crate) fn len_of_direction(&self, direction: Direction) -> usize {
83 match direction {
84 Direction::Sent => self.sent.len(),
85 Direction::Received => self.received.len(),
86 }
87 }
88
89 pub fn length(&self) -> TranscriptLength {
91 TranscriptLength {
92 sent: self.sent.len() as u32,
93 received: self.received.len() as u32,
94 }
95 }
96
97 pub fn get(&self, direction: Direction, idx: &RangeSet<usize>) -> Option<Subsequence> {
100 let data = match direction {
101 Direction::Sent => &self.sent,
102 Direction::Received => &self.received,
103 };
104
105 if idx.end().unwrap_or(0) > data.len() {
106 return None;
107 }
108
109 Some(
110 Subsequence::new(idx.clone(), data.index_ranges(idx))
111 .expect("data is same length as index"),
112 )
113 }
114
115 pub fn to_partial(
126 &self,
127 sent_idx: RangeSet<usize>,
128 recv_idx: RangeSet<usize>,
129 ) -> PartialTranscript {
130 let mut sent = vec![0; self.sent.len()];
131 let mut received = vec![0; self.received.len()];
132
133 for range in sent_idx.iter_ranges() {
134 sent[range.clone()].copy_from_slice(&self.sent[range]);
135 }
136
137 for range in recv_idx.iter_ranges() {
138 received[range.clone()].copy_from_slice(&self.received[range]);
139 }
140
141 PartialTranscript {
142 sent,
143 received,
144 sent_authed_idx: sent_idx,
145 received_authed_idx: recv_idx,
146 }
147 }
148}
149
150#[derive(Debug, Clone, Serialize, Deserialize)]
155#[serde(try_from = "CompressedPartialTranscript")]
156#[serde(into = "CompressedPartialTranscript")]
157#[cfg_attr(test, derive(PartialEq))]
158pub struct PartialTranscript {
159 sent: Vec<u8>,
161 received: Vec<u8>,
163 sent_authed_idx: RangeSet<usize>,
165 received_authed_idx: RangeSet<usize>,
167}
168
169#[derive(Debug, Clone, Serialize, Deserialize)]
171#[serde(try_from = "validation::CompressedPartialTranscriptUnchecked")]
172pub struct CompressedPartialTranscript {
173 sent_authed: Vec<u8>,
175 received_authed: Vec<u8>,
177 sent_idx: RangeSet<usize>,
179 recv_idx: RangeSet<usize>,
181 sent_total: usize,
183 recv_total: usize,
185}
186
187impl From<PartialTranscript> for CompressedPartialTranscript {
188 fn from(uncompressed: PartialTranscript) -> Self {
189 Self {
190 sent_authed: uncompressed
191 .sent
192 .index_ranges(&uncompressed.sent_authed_idx),
193 received_authed: uncompressed
194 .received
195 .index_ranges(&uncompressed.received_authed_idx),
196 sent_idx: uncompressed.sent_authed_idx,
197 recv_idx: uncompressed.received_authed_idx,
198 sent_total: uncompressed.sent.len(),
199 recv_total: uncompressed.received.len(),
200 }
201 }
202}
203
204impl From<CompressedPartialTranscript> for PartialTranscript {
205 fn from(compressed: CompressedPartialTranscript) -> Self {
206 let mut sent = vec![0; compressed.sent_total];
207 let mut received = vec![0; compressed.recv_total];
208
209 let mut offset = 0;
210
211 for range in compressed.sent_idx.iter_ranges() {
212 sent[range.clone()]
213 .copy_from_slice(&compressed.sent_authed[offset..offset + range.len()]);
214 offset += range.len();
215 }
216
217 let mut offset = 0;
218
219 for range in compressed.recv_idx.iter_ranges() {
220 received[range.clone()]
221 .copy_from_slice(&compressed.received_authed[offset..offset + range.len()]);
222 offset += range.len();
223 }
224
225 Self {
226 sent,
227 received,
228 sent_authed_idx: compressed.sent_idx,
229 received_authed_idx: compressed.recv_idx,
230 }
231 }
232}
233
234impl PartialTranscript {
235 pub fn new(sent_len: usize, received_len: usize) -> Self {
242 Self {
243 sent: vec![0; sent_len],
244 received: vec![0; received_len],
245 sent_authed_idx: RangeSet::default(),
246 received_authed_idx: RangeSet::default(),
247 }
248 }
249
250 pub fn len_sent(&self) -> usize {
252 self.sent.len()
253 }
254
255 pub fn len_received(&self) -> usize {
257 self.received.len()
258 }
259
260 pub fn is_complete(&self) -> bool {
262 self.sent_authed_idx.len() == self.sent.len()
263 && self.received_authed_idx.len() == self.received.len()
264 }
265
266 pub fn contains(&self, direction: Direction, idx: &RangeSet<usize>) -> bool {
268 match direction {
269 Direction::Sent => idx.end().unwrap_or(0) <= self.sent.len(),
270 Direction::Received => idx.end().unwrap_or(0) <= self.received.len(),
271 }
272 }
273
274 pub fn sent_unsafe(&self) -> &[u8] {
282 &self.sent
283 }
284
285 pub fn received_unsafe(&self) -> &[u8] {
293 &self.received
294 }
295
296 pub fn sent_authed(&self) -> &RangeSet<usize> {
298 &self.sent_authed_idx
299 }
300
301 pub fn received_authed(&self) -> &RangeSet<usize> {
303 &self.received_authed_idx
304 }
305
306 pub fn sent_unauthed(&self) -> RangeSet<usize> {
308 (0..self.sent.len()).difference(&self.sent_authed_idx)
309 }
310
311 pub fn received_unauthed(&self) -> RangeSet<usize> {
313 (0..self.received.len()).difference(&self.received_authed_idx)
314 }
315
316 pub fn iter(&self, direction: Direction) -> impl Iterator<Item = u8> + '_ {
318 let (data, authed) = match direction {
319 Direction::Sent => (&self.sent, &self.sent_authed_idx),
320 Direction::Received => (&self.received, &self.received_authed_idx),
321 };
322
323 authed.iter().map(|i| data[i])
324 }
325
326 pub fn union_transcript(&mut self, other: &PartialTranscript) {
332 assert_eq!(
333 self.sent.len(),
334 other.sent.len(),
335 "sent data are not the same length"
336 );
337 assert_eq!(
338 self.received.len(),
339 other.received.len(),
340 "received data are not the same length"
341 );
342
343 for range in other
344 .sent_authed_idx
345 .difference(&self.sent_authed_idx)
346 .iter_ranges()
347 {
348 self.sent[range.clone()].copy_from_slice(&other.sent[range]);
349 }
350
351 for range in other
352 .received_authed_idx
353 .difference(&self.received_authed_idx)
354 .iter_ranges()
355 {
356 self.received[range.clone()].copy_from_slice(&other.received[range]);
357 }
358
359 self.sent_authed_idx = self.sent_authed_idx.union(&other.sent_authed_idx);
360 self.received_authed_idx = self.received_authed_idx.union(&other.received_authed_idx);
361 }
362
363 pub fn union_subsequence(&mut self, direction: Direction, seq: &Subsequence) {
369 match direction {
370 Direction::Sent => {
371 seq.copy_to(&mut self.sent);
372 self.sent_authed_idx = self.sent_authed_idx.union(&seq.idx);
373 }
374 Direction::Received => {
375 seq.copy_to(&mut self.received);
376 self.received_authed_idx = self.received_authed_idx.union(&seq.idx);
377 }
378 }
379 }
380
381 pub fn set_unauthed(&mut self, value: u8) {
387 for range in self.sent_unauthed().iter_ranges() {
388 self.sent[range].fill(value);
389 }
390 for range in self.received_unauthed().iter_ranges() {
391 self.received[range].fill(value);
392 }
393 }
394
395 pub fn set_unauthed_range(&mut self, value: u8, direction: Direction, range: Range<usize>) {
403 match direction {
404 Direction::Sent => {
405 for range in range.difference(&self.sent_authed_idx).iter_ranges() {
406 self.sent[range].fill(value);
407 }
408 }
409 Direction::Received => {
410 for range in range.difference(&self.received_authed_idx).iter_ranges() {
411 self.received[range].fill(value);
412 }
413 }
414 }
415 }
416}
417
418#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
423pub enum Direction {
424 Sent = 0x00,
426 Received = 0x01,
428}
429
430impl fmt::Display for Direction {
431 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
432 match self {
433 Direction::Sent => write!(f, "sent"),
434 Direction::Received => write!(f, "received"),
435 }
436 }
437}
438
439#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
441#[serde(try_from = "validation::SubsequenceUnchecked")]
442pub struct Subsequence {
443 idx: RangeSet<usize>,
445 data: Vec<u8>,
447}
448
449impl Subsequence {
450 pub fn new(idx: RangeSet<usize>, data: Vec<u8>) -> Result<Self, InvalidSubsequence> {
452 if idx.len() != data.len() {
453 return Err(InvalidSubsequence(
454 "index length does not match data length",
455 ));
456 }
457
458 Ok(Self { idx, data })
459 }
460
461 pub fn index(&self) -> &RangeSet<usize> {
463 &self.idx
464 }
465
466 pub fn data(&self) -> &[u8] {
468 &self.data
469 }
470
471 #[allow(clippy::len_without_is_empty)]
473 pub fn len(&self) -> usize {
474 self.data.len()
475 }
476
477 pub fn into_parts(self) -> (RangeSet<usize>, Vec<u8>) {
479 (self.idx, self.data)
480 }
481
482 pub(crate) fn copy_to(&self, dest: &mut [u8]) {
488 let mut offset = 0;
489 for range in self.idx.iter_ranges() {
490 dest[range.clone()].copy_from_slice(&self.data[offset..offset + range.len()]);
491 offset += range.len();
492 }
493 }
494}
495
496#[derive(Debug, thiserror::Error)]
498#[error("invalid subsequence: {0}")]
499pub struct InvalidSubsequence(&'static str);
500
501mod validation {
502 use super::*;
503
504 #[derive(Debug, Deserialize)]
505 pub(super) struct SubsequenceUnchecked {
506 idx: RangeSet<usize>,
507 data: Vec<u8>,
508 }
509
510 impl TryFrom<SubsequenceUnchecked> for Subsequence {
511 type Error = InvalidSubsequence;
512
513 fn try_from(unchecked: SubsequenceUnchecked) -> Result<Self, Self::Error> {
514 Self::new(unchecked.idx, unchecked.data)
515 }
516 }
517
518 #[derive(Debug, thiserror::Error)]
520 #[error("invalid compressed partial transcript: {0}")]
521 pub struct InvalidCompressedPartialTranscript(&'static str);
522
523 #[derive(Debug, Deserialize)]
524 #[cfg_attr(test, derive(Serialize))]
525 pub(super) struct CompressedPartialTranscriptUnchecked {
526 sent_authed: Vec<u8>,
527 received_authed: Vec<u8>,
528 sent_idx: RangeSet<usize>,
529 recv_idx: RangeSet<usize>,
530 sent_total: usize,
531 recv_total: usize,
532 }
533
534 impl TryFrom<CompressedPartialTranscriptUnchecked> for CompressedPartialTranscript {
535 type Error = InvalidCompressedPartialTranscript;
536
537 fn try_from(unchecked: CompressedPartialTranscriptUnchecked) -> Result<Self, Self::Error> {
538 if unchecked.sent_authed.len() != unchecked.sent_idx.len()
539 || unchecked.received_authed.len() != unchecked.recv_idx.len()
540 {
541 return Err(InvalidCompressedPartialTranscript(
542 "lengths of index and data don't match",
543 ));
544 }
545
546 if unchecked.sent_idx.end().unwrap_or(0) > unchecked.sent_total
547 || unchecked.recv_idx.end().unwrap_or(0) > unchecked.recv_total
548 {
549 return Err(InvalidCompressedPartialTranscript(
550 "ranges are not in bounds of the data",
551 ));
552 }
553
554 Ok(Self {
555 received_authed: unchecked.received_authed,
556 recv_idx: unchecked.recv_idx,
557 recv_total: unchecked.recv_total,
558 sent_authed: unchecked.sent_authed,
559 sent_idx: unchecked.sent_idx,
560 sent_total: unchecked.sent_total,
561 })
562 }
563 }
564
565 #[cfg(test)]
566 mod tests {
567 use rstest::{fixture, rstest};
568
569 use super::*;
570
571 #[fixture]
572 fn partial_transcript() -> CompressedPartialTranscriptUnchecked {
573 CompressedPartialTranscriptUnchecked {
574 received_authed: vec![1, 2, 3, 11, 12, 13],
575 sent_authed: vec![4, 5, 6, 14, 15, 16],
576 recv_idx: RangeSet::from([1..4, 11..14]),
577 sent_idx: RangeSet::from([4..7, 14..17]),
578 sent_total: 20,
579 recv_total: 20,
580 }
581 }
582
583 #[rstest]
584 fn test_partial_transcript_valid(partial_transcript: CompressedPartialTranscriptUnchecked) {
585 let bytes = bincode::serialize(&partial_transcript).unwrap();
586 let transcript: Result<CompressedPartialTranscript, Box<bincode::ErrorKind>> =
587 bincode::deserialize(&bytes);
588 assert!(transcript.is_ok());
589 }
590
591 #[rstest]
592 fn test_partial_transcript_invalid_lengths(
595 mut partial_transcript: CompressedPartialTranscriptUnchecked,
596 ) {
597 let mut old = partial_transcript.sent_authed;
599 old.extend([1]);
600 partial_transcript.sent_authed = old;
601
602 let bytes = bincode::serialize(&partial_transcript).unwrap();
603 let transcript: Result<CompressedPartialTranscript, Box<bincode::ErrorKind>> =
604 bincode::deserialize(&bytes);
605 assert!(transcript.is_err());
606 }
607
608 #[rstest]
609 fn test_partial_transcript_invalid_ranges(
611 mut partial_transcript: CompressedPartialTranscriptUnchecked,
612 ) {
613 let end = partial_transcript
615 .sent_idx
616 .iter_ranges()
617 .next_back()
618 .unwrap()
619 .end;
620
621 partial_transcript.sent_total = end - 1;
622
623 let bytes = bincode::serialize(&partial_transcript).unwrap();
624 let transcript: Result<CompressedPartialTranscript, Box<bincode::ErrorKind>> =
625 bincode::deserialize(&bytes);
626 assert!(transcript.is_err());
627 }
628 }
629}
630
631#[cfg(test)]
632mod tests {
633 use rstest::{fixture, rstest};
634
635 use super::*;
636
637 #[fixture]
638 fn transcript() -> Transcript {
639 Transcript::new(
640 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
641 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
642 )
643 }
644
645 #[fixture]
646 fn partial_transcript() -> PartialTranscript {
647 transcript().to_partial(RangeSet::from([1..4, 6..9]), RangeSet::from([2..5, 7..10]))
648 }
649
650 #[rstest]
651 fn test_transcript_get_subsequence(transcript: Transcript) {
652 let subseq = transcript
653 .get(Direction::Received, &RangeSet::from([0..4, 7..10]))
654 .unwrap();
655 assert_eq!(subseq.data, vec![0, 1, 2, 3, 7, 8, 9]);
656
657 let subseq = transcript
658 .get(Direction::Sent, &RangeSet::from([0..4, 9..12]))
659 .unwrap();
660 assert_eq!(subseq.data, vec![0, 1, 2, 3, 9, 10, 11]);
661
662 let subseq = transcript.get(Direction::Received, &RangeSet::from([0..4, 7..10, 11..13]));
663 assert_eq!(subseq, None);
664
665 let subseq = transcript.get(Direction::Sent, &RangeSet::from([0..4, 7..10, 11..13]));
666 assert_eq!(subseq, None);
667 }
668
669 #[rstest]
670 fn test_partial_transcript_serialization_ok(partial_transcript: PartialTranscript) {
671 let bytes = bincode::serialize(&partial_transcript).unwrap();
672 let deserialized_transcript: PartialTranscript = bincode::deserialize(&bytes).unwrap();
673 assert_eq!(partial_transcript, deserialized_transcript);
674 }
675
676 #[rstest]
677 fn test_transcript_to_partial_success(transcript: Transcript) {
678 let partial = transcript.to_partial(RangeSet::from(0..2), RangeSet::from(3..7));
679 assert_eq!(partial.sent_unsafe(), [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
680 assert_eq!(
681 partial.received_unsafe(),
682 [0, 0, 0, 3, 4, 5, 6, 0, 0, 0, 0, 0]
683 );
684 }
685
686 #[rstest]
687 #[should_panic]
688 fn test_transcript_to_partial_failure(transcript: Transcript) {
689 let _ = transcript.to_partial(RangeSet::from(0..14), RangeSet::from(3..7));
690 }
691
692 #[rstest]
693 fn test_partial_transcript_contains(transcript: Transcript) {
694 let partial = transcript.to_partial(RangeSet::from(0..2), RangeSet::from(3..7));
695 assert!(partial.contains(Direction::Sent, &RangeSet::from([0..5, 7..10])));
696 assert!(!partial.contains(Direction::Received, &RangeSet::from([4..6, 7..13])))
697 }
698
699 #[rstest]
700 fn test_partial_transcript_unauthed(transcript: Transcript) {
701 let partial = transcript.to_partial(RangeSet::from(0..2), RangeSet::from(3..7));
702 assert_eq!(partial.sent_unauthed(), RangeSet::from(2..12));
703 assert_eq!(partial.received_unauthed(), RangeSet::from([0..3, 7..12]));
704 }
705
706 #[rstest]
707 fn test_partial_transcript_union_success(transcript: Transcript) {
708 let mut simple_partial = transcript.to_partial(RangeSet::from(0..2), RangeSet::from(3..7));
710
711 let other_simple_partial =
712 transcript.to_partial(RangeSet::from(3..5), RangeSet::from(1..2));
713
714 simple_partial.union_transcript(&other_simple_partial);
715
716 assert_eq!(
717 simple_partial.sent_unsafe(),
718 [0, 1, 0, 3, 4, 0, 0, 0, 0, 0, 0, 0]
719 );
720 assert_eq!(
721 simple_partial.received_unsafe(),
722 [0, 1, 0, 3, 4, 5, 6, 0, 0, 0, 0, 0]
723 );
724 assert_eq!(simple_partial.sent_authed(), &RangeSet::from([0..2, 3..5]));
725 assert_eq!(
726 simple_partial.received_authed(),
727 &RangeSet::from([1..2, 3..7])
728 );
729
730 let another_simple_partial =
733 transcript.to_partial(RangeSet::from(1..4), RangeSet::from(6..9));
734
735 simple_partial.union_transcript(&another_simple_partial);
736
737 assert_eq!(
738 simple_partial.sent_unsafe(),
739 [0, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0]
740 );
741 assert_eq!(
742 simple_partial.received_unsafe(),
743 [0, 1, 0, 3, 4, 5, 6, 7, 8, 0, 0, 0]
744 );
745 assert_eq!(simple_partial.sent_authed(), &RangeSet::from(0..5));
746 assert_eq!(
747 simple_partial.received_authed(),
748 &RangeSet::from([1..2, 3..9])
749 );
750
751 let mut overlap_partial = transcript.to_partial(RangeSet::from(4..6), RangeSet::from(3..7));
753
754 let other_overlap_partial =
755 transcript.to_partial(RangeSet::from(3..5), RangeSet::from(5..9));
756
757 overlap_partial.union_transcript(&other_overlap_partial);
758
759 assert_eq!(
760 overlap_partial.sent_unsafe(),
761 [0, 0, 0, 3, 4, 5, 0, 0, 0, 0, 0, 0]
762 );
763 assert_eq!(
764 overlap_partial.received_unsafe(),
765 [0, 0, 0, 3, 4, 5, 6, 7, 8, 0, 0, 0]
766 );
767 assert_eq!(overlap_partial.sent_authed(), &RangeSet::from([3..5, 4..6]));
768 assert_eq!(
769 overlap_partial.received_authed(),
770 &RangeSet::from([3..7, 5..9])
771 );
772
773 let mut equal_partial = transcript.to_partial(RangeSet::from(4..6), RangeSet::from(3..7));
775
776 let other_equal_partial = transcript.to_partial(RangeSet::from(4..6), RangeSet::from(3..7));
777
778 equal_partial.union_transcript(&other_equal_partial);
779
780 assert_eq!(
781 equal_partial.sent_unsafe(),
782 [0, 0, 0, 0, 4, 5, 0, 0, 0, 0, 0, 0]
783 );
784 assert_eq!(
785 equal_partial.received_unsafe(),
786 [0, 0, 0, 3, 4, 5, 6, 0, 0, 0, 0, 0]
787 );
788 assert_eq!(equal_partial.sent_authed(), &RangeSet::from(4..6));
789 assert_eq!(equal_partial.received_authed(), &RangeSet::from(3..7));
790
791 let mut subset_partial =
793 transcript.to_partial(RangeSet::from(4..10), RangeSet::from(3..11));
794
795 let other_subset_partial =
796 transcript.to_partial(RangeSet::from(6..9), RangeSet::from(5..6));
797
798 subset_partial.union_transcript(&other_subset_partial);
799
800 assert_eq!(
801 subset_partial.sent_unsafe(),
802 [0, 0, 0, 0, 4, 5, 6, 7, 8, 9, 0, 0]
803 );
804 assert_eq!(
805 subset_partial.received_unsafe(),
806 [0, 0, 0, 3, 4, 5, 6, 7, 8, 9, 10, 0]
807 );
808 assert_eq!(subset_partial.sent_authed(), &RangeSet::from(4..10));
809 assert_eq!(subset_partial.received_authed(), &RangeSet::from(3..11));
810 }
811
812 #[rstest]
813 #[should_panic]
814 fn test_partial_transcript_union_failure(transcript: Transcript) {
815 let mut partial = transcript.to_partial(RangeSet::from(4..10), RangeSet::from(3..11));
816
817 let other_transcript = Transcript::new(
818 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
819 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
820 );
821
822 let other_partial = other_transcript.to_partial(RangeSet::from(6..9), RangeSet::from(5..6));
823
824 partial.union_transcript(&other_partial);
825 }
826
827 #[rstest]
828 fn test_partial_transcript_union_subseq_success(transcript: Transcript) {
829 let mut partial = transcript.to_partial(RangeSet::from(4..10), RangeSet::from(3..11));
830 let sent_seq =
831 Subsequence::new(RangeSet::from([0..3, 5..7]), [0, 1, 2, 5, 6].into()).unwrap();
832 let recv_seq =
833 Subsequence::new(RangeSet::from([0..4, 5..7]), [0, 1, 2, 3, 5, 6].into()).unwrap();
834
835 partial.union_subsequence(Direction::Sent, &sent_seq);
836 partial.union_subsequence(Direction::Received, &recv_seq);
837
838 assert_eq!(partial.sent_unsafe(), [0, 1, 2, 0, 4, 5, 6, 7, 8, 9, 0, 0]);
839 assert_eq!(
840 partial.received_unsafe(),
841 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0]
842 );
843 assert_eq!(partial.sent_authed(), &RangeSet::from([0..3, 4..10]));
844 assert_eq!(partial.received_authed(), &RangeSet::from(0..11));
845
846 let other_sent_seq = Subsequence::new(RangeSet::from(0..3), [3, 2, 1].into()).unwrap();
848
849 partial.union_subsequence(Direction::Sent, &other_sent_seq);
850 assert_eq!(partial.sent_unsafe(), [3, 2, 1, 0, 4, 5, 6, 7, 8, 9, 0, 0]);
851 assert_eq!(partial.sent_authed(), &RangeSet::from([0..3, 4..10]));
852 }
853
854 #[rstest]
855 #[should_panic]
856 fn test_partial_transcript_union_subseq_failure(transcript: Transcript) {
857 let mut partial = transcript.to_partial(RangeSet::from(4..10), RangeSet::from(3..11));
858
859 let sent_seq =
860 Subsequence::new(RangeSet::from([0..3, 13..15]), [0, 1, 2, 5, 6].into()).unwrap();
861
862 partial.union_subsequence(Direction::Sent, &sent_seq);
863 }
864
865 #[rstest]
866 fn test_partial_transcript_set_unauthed_range(transcript: Transcript) {
867 let mut partial = transcript.to_partial(RangeSet::from(4..10), RangeSet::from(3..7));
868
869 partial.set_unauthed_range(7, Direction::Sent, 2..5);
870 partial.set_unauthed_range(5, Direction::Sent, 0..2);
871 partial.set_unauthed_range(3, Direction::Received, 4..6);
872 partial.set_unauthed_range(1, Direction::Received, 3..7);
873
874 assert_eq!(partial.sent_unsafe(), [5, 5, 7, 7, 4, 5, 6, 7, 8, 9, 0, 0]);
875 assert_eq!(
876 partial.received_unsafe(),
877 [0, 0, 0, 3, 4, 5, 6, 0, 0, 0, 0, 0]
878 );
879 }
880
881 #[rstest]
882 #[should_panic]
883 fn test_subsequence_new_invalid_len() {
884 let _ = Subsequence::new(RangeSet::from([0..3, 5..8]), [0, 1, 2, 5, 6].into()).unwrap();
885 }
886
887 #[rstest]
888 #[should_panic]
889 fn test_subsequence_copy_to_invalid_len() {
890 let seq = Subsequence::new(RangeSet::from([0..3, 5..7]), [0, 1, 2, 5, 6].into()).unwrap();
891
892 let mut data: [u8; 3] = [0, 1, 2];
893 seq.copy_to(&mut data);
894 }
895}