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