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