1mod commit;
22pub mod hash;
23mod proof;
24#[cfg(test)]
25pub(crate) mod test;
26mod tls;
27
28use std::{fmt, ops::Range};
29
30use rangeset::{
31 iter::RangeIterator,
32 ops::{Index, Set},
33 set::RangeSet,
34};
35use serde::{Deserialize, Serialize};
36
37use crate::connection::TranscriptLength;
38
39pub use commit::{
40 TranscriptCommitConfig, TranscriptCommitConfigBuilder, TranscriptCommitConfigBuilderError,
41 TranscriptCommitRequest, TranscriptCommitment, TranscriptCommitmentKind, TranscriptSecret,
42};
43pub use proof::{
44 TranscriptProof, TranscriptProofBuilder, TranscriptProofBuilderError, TranscriptProofError,
45};
46pub use tls::{ContentType, Record, TlsTranscript, TlsTranscriptBuilder, TlsTranscriptError};
47
48#[derive(Clone, Serialize, Deserialize)]
51pub struct Transcript {
52 sent: Vec<u8>,
54 received: Vec<u8>,
56}
57
58opaque_debug::implement!(Transcript);
59
60impl Transcript {
61 pub fn new(sent: impl Into<Vec<u8>>, received: impl Into<Vec<u8>>) -> Self {
63 Self {
64 sent: sent.into(),
65 received: received.into(),
66 }
67 }
68
69 pub fn sent(&self) -> &[u8] {
71 &self.sent
72 }
73
74 pub fn received(&self) -> &[u8] {
76 &self.received
77 }
78
79 #[allow(clippy::len_without_is_empty)]
81 pub fn len(&self) -> (usize, usize) {
82 (self.sent.len(), self.received.len())
83 }
84
85 pub(crate) fn len_of_direction(&self, direction: Direction) -> usize {
87 match direction {
88 Direction::Sent => self.sent.len(),
89 Direction::Received => self.received.len(),
90 }
91 }
92
93 pub fn length(&self) -> TranscriptLength {
95 TranscriptLength {
96 sent: self.sent.len() as u32,
97 received: self.received.len() as u32,
98 }
99 }
100
101 pub fn get(&self, direction: Direction, idx: &RangeSet<usize>) -> Option<Subsequence> {
104 let data = match direction {
105 Direction::Sent => &self.sent,
106 Direction::Received => &self.received,
107 };
108
109 if idx.end().unwrap_or(0) > data.len() {
110 return None;
111 }
112
113 Some(
114 Subsequence::new(
115 idx.clone(),
116 data.index(idx).fold(Vec::new(), |mut acc, s| {
117 acc.extend_from_slice(s);
118 acc
119 }),
120 )
121 .expect("data is same length as index"),
122 )
123 }
124
125 pub fn to_partial(
136 &self,
137 sent_idx: RangeSet<usize>,
138 recv_idx: RangeSet<usize>,
139 ) -> PartialTranscript {
140 let sent_authed = sent_idx
141 .iter()
142 .flat_map(|range| self.sent[range].iter().copied())
143 .collect();
144 let received_authed = recv_idx
145 .iter()
146 .flat_map(|range| self.received[range].iter().copied())
147 .collect();
148
149 PartialTranscript {
150 sent_authed,
151 received_authed,
152 sent_idx,
153 recv_idx,
154 sent_total: self.sent.len(),
155 recv_total: self.received.len(),
156 }
157 }
158}
159
160#[derive(Debug, Clone, Serialize, Deserialize)]
170#[serde(try_from = "validation::PartialTranscriptUnchecked")]
171#[cfg_attr(test, derive(PartialEq))]
172pub struct PartialTranscript {
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 PartialTranscript {
188 pub fn sent_authed(&self) -> &RangeSet<usize> {
190 &self.sent_idx
191 }
192
193 pub fn received_authed(&self) -> &RangeSet<usize> {
195 &self.recv_idx
196 }
197
198 pub(crate) fn sent_authed_bytes(&self) -> &[u8] {
200 &self.sent_authed
201 }
202
203 pub(crate) fn received_authed_bytes(&self) -> &[u8] {
205 &self.received_authed
206 }
207
208 #[allow(clippy::len_without_is_empty)]
210 pub fn len_sent(&self) -> usize {
211 self.sent_total
212 }
213
214 #[allow(clippy::len_without_is_empty)]
216 pub fn len_received(&self) -> usize {
217 self.recv_total
218 }
219
220 pub fn union_transcript(&mut self, other: &PartialTranscript) {
230 assert_eq!(
231 self.sent_total, other.sent_total,
232 "sent data are not the same length"
233 );
234 assert_eq!(
235 self.recv_total, other.recv_total,
236 "received data are not the same length"
237 );
238
239 let (sent_idx, sent_authed) = overlay(
240 &self.sent_idx,
241 &self.sent_authed,
242 &other.sent_idx,
243 &other.sent_authed,
244 );
245 let (recv_idx, received_authed) = overlay(
246 &self.recv_idx,
247 &self.received_authed,
248 &other.recv_idx,
249 &other.received_authed,
250 );
251
252 self.sent_idx = sent_idx;
253 self.sent_authed = sent_authed;
254 self.recv_idx = recv_idx;
255 self.received_authed = received_authed;
256 }
257
258 pub fn union_subsequence(&mut self, direction: Direction, seq: &Subsequence) {
267 let total = match direction {
268 Direction::Sent => self.sent_total,
269 Direction::Received => self.recv_total,
270 };
271
272 if seq.index().end().unwrap_or(0) > total {
273 panic!("subsequence is out of bounds of the transcript");
274 }
275
276 match direction {
277 Direction::Sent => {
278 let (idx, data) =
279 overlay(seq.index(), seq.data(), &self.sent_idx, &self.sent_authed);
280 self.sent_idx = idx;
281 self.sent_authed = data;
282 }
283 Direction::Received => {
284 let (idx, data) = overlay(
285 seq.index(),
286 seq.data(),
287 &self.recv_idx,
288 &self.received_authed,
289 );
290 self.recv_idx = idx;
291 self.received_authed = data;
292 }
293 }
294 }
295
296 pub(crate) fn locate(&self, direction: Direction, range: &Range<usize>) -> Option<&[u8]> {
301 let (idx, bytes) = match direction {
302 Direction::Sent => (&self.sent_idx, self.sent_authed_bytes()),
303 Direction::Received => (&self.recv_idx, self.received_authed_bytes()),
304 };
305
306 locate(idx, bytes, range)
307 }
308
309 pub fn sent_unsafe(&self, expected: usize) -> Result<Vec<u8>, InvalidTranscriptLength> {
322 self.expand(Direction::Sent, expected)
323 }
324
325 pub fn received_unsafe(&self, expected: usize) -> Result<Vec<u8>, InvalidTranscriptLength> {
337 self.expand(Direction::Received, expected)
338 }
339
340 fn expand(
341 &self,
342 direction: Direction,
343 expected: usize,
344 ) -> Result<Vec<u8>, InvalidTranscriptLength> {
345 let (idx, bytes, total) = match direction {
346 Direction::Sent => (&self.sent_idx, self.sent_authed_bytes(), self.sent_total),
347 Direction::Received => (
348 &self.recv_idx,
349 self.received_authed_bytes(),
350 self.recv_total,
351 ),
352 };
353
354 if total != expected {
355 return Err(InvalidTranscriptLength {
356 expected,
357 actual: total,
358 });
359 }
360
361 let mut out = vec![0; expected];
362 let mut offset = 0;
363 for range in idx.iter() {
364 out[range.clone()].copy_from_slice(&bytes[offset..offset + range.len()]);
365 offset += range.len();
366 }
367
368 Ok(out)
369 }
370
371 pub(crate) fn materialize_range(&self, direction: Direction, range: &Range<usize>) -> Vec<u8> {
374 let (idx, bytes) = match direction {
375 Direction::Sent => (&self.sent_idx, self.sent_authed_bytes()),
376 Direction::Received => (&self.recv_idx, self.received_authed_bytes()),
377 };
378
379 let mut out = Vec::with_capacity(range.len());
380 let mut pos = range.start;
381 let mut offset = 0;
382
383 for r in idx.iter() {
384 if r.end <= pos {
385 offset += r.len();
386 continue;
387 }
388 if r.start >= range.end {
389 break;
390 }
391
392 if pos < r.start {
393 let end = r.start.min(range.end);
394 out.resize(out.len() + (end - pos), 0);
395 pos = end;
396 }
397
398 let start = pos.max(r.start);
399 let end = r.end.min(range.end);
400 if start < end {
401 out.extend_from_slice(&bytes[offset + (start - r.start)..offset + (end - r.start)]);
402 pos = end;
403 }
404
405 offset += r.len();
406
407 if pos >= range.end {
408 break;
409 }
410 }
411
412 if pos < range.end {
413 out.resize(out.len() + (range.end - pos), 0);
414 }
415
416 out
417 }
418}
419
420#[derive(Debug, thiserror::Error)]
422#[error("invalid transcript length: expected {expected}, got {actual}")]
423pub struct InvalidTranscriptLength {
424 pub expected: usize,
426 pub actual: usize,
428}
429
430fn locate<'a>(idx: &RangeSet<usize>, bytes: &'a [u8], range: &Range<usize>) -> Option<&'a [u8]> {
435 let mut offset = 0;
436 for r in idx.iter() {
437 if range.start >= r.start && range.end <= r.end {
438 let start = offset + (range.start - r.start);
439 return Some(&bytes[start..start + range.len()]);
440 }
441 offset += r.len();
442 }
443 None
444}
445
446fn overlay(
453 win_idx: &RangeSet<usize>,
454 win_bytes: &[u8],
455 lose_idx: &RangeSet<usize>,
456 lose_bytes: &[u8],
457) -> (RangeSet<usize>, Vec<u8>) {
458 let delta = lose_idx.difference(win_idx).into_set();
459 let lose_delta = subset_bytes(lose_idx, lose_bytes, &delta);
460 merge_disjoint(win_idx, win_bytes, &delta, &lose_delta)
461}
462
463fn subset_bytes(idx: &RangeSet<usize>, bytes: &[u8], subset: &RangeSet<usize>) -> Vec<u8> {
468 let mut out = Vec::new();
469 let mut offset = 0;
470 let mut sub = subset.iter().peekable();
471
472 for range in idx.iter() {
473 while let Some(s) = sub.peek().cloned() {
474 if s.end <= range.start {
475 sub.next();
476 continue;
477 }
478 if s.start >= range.end {
479 break;
480 }
481
482 let start = s.start.max(range.start);
483 let end = s.end.min(range.end);
484 out.extend_from_slice(
485 &bytes[offset + (start - range.start)..offset + (end - range.start)],
486 );
487
488 if s.end <= range.end {
489 sub.next();
490 } else {
491 break;
492 }
493 }
494
495 offset += range.len();
496 }
497
498 out
499}
500
501fn merge_disjoint(
503 a_idx: &RangeSet<usize>,
504 a_bytes: &[u8],
505 b_idx: &RangeSet<usize>,
506 b_bytes: &[u8],
507) -> (RangeSet<usize>, Vec<u8>) {
508 let mut ranges = Vec::new();
509 let mut bytes = Vec::with_capacity(a_bytes.len() + b_bytes.len());
510
511 let mut a = a_idx.iter().peekable();
512 let mut b = b_idx.iter().peekable();
513 let mut ao = 0;
514 let mut bo = 0;
515
516 loop {
517 let take_a = match (a.peek(), b.peek()) {
518 (Some(a), Some(b)) => a.start < b.start,
519 (Some(_), None) => true,
520 (None, Some(_)) => false,
521 (None, None) => break,
522 };
523
524 if take_a {
525 let range = a.next().unwrap();
526 bytes.extend_from_slice(&a_bytes[ao..ao + range.len()]);
527 ao += range.len();
528 ranges.push(range);
529 } else {
530 let range = b.next().unwrap();
531 bytes.extend_from_slice(&b_bytes[bo..bo + range.len()]);
532 bo += range.len();
533 ranges.push(range);
534 }
535 }
536
537 (RangeSet::new_from_slice(&ranges), bytes)
538}
539
540impl PartialTranscript {
541 pub fn new(sent_len: usize, received_len: usize) -> Self {
548 Self {
549 sent_authed: Vec::new(),
550 received_authed: Vec::new(),
551 sent_idx: RangeSet::default(),
552 recv_idx: RangeSet::default(),
553 sent_total: sent_len,
554 recv_total: received_len,
555 }
556 }
557
558 pub fn is_complete(&self) -> bool {
560 self.sent_idx.len() == self.sent_total && self.recv_idx.len() == self.recv_total
561 }
562
563 pub fn contains(&self, direction: Direction, idx: &RangeSet<usize>) -> bool {
565 match direction {
566 Direction::Sent => idx.end().unwrap_or(0) <= self.sent_total,
567 Direction::Received => idx.end().unwrap_or(0) <= self.recv_total,
568 }
569 }
570
571 pub fn sent_unauthed(&self) -> RangeSet<usize> {
573 (0..self.sent_total).difference(&self.sent_idx).into_set()
574 }
575
576 pub fn received_unauthed(&self) -> RangeSet<usize> {
578 (0..self.recv_total).difference(&self.recv_idx).into_set()
579 }
580
581 pub fn iter(&self, direction: Direction) -> impl Iterator<Item = u8> + '_ {
583 let bytes = match direction {
584 Direction::Sent => &self.sent_authed,
585 Direction::Received => &self.received_authed,
586 };
587
588 bytes.iter().copied()
589 }
590}
591
592#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
597pub enum Direction {
598 Sent = 0x00,
600 Received = 0x01,
602}
603
604impl fmt::Display for Direction {
605 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
606 match self {
607 Direction::Sent => write!(f, "sent"),
608 Direction::Received => write!(f, "received"),
609 }
610 }
611}
612
613#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
615#[serde(try_from = "validation::SubsequenceUnchecked")]
616pub struct Subsequence {
617 idx: RangeSet<usize>,
619 data: Vec<u8>,
621}
622
623impl Subsequence {
624 pub fn new(idx: RangeSet<usize>, data: Vec<u8>) -> Result<Self, InvalidSubsequence> {
626 if idx.len() != data.len() {
627 return Err(InvalidSubsequence(
628 "index length does not match data length",
629 ));
630 }
631
632 Ok(Self { idx, data })
633 }
634
635 pub fn index(&self) -> &RangeSet<usize> {
637 &self.idx
638 }
639
640 pub fn data(&self) -> &[u8] {
642 &self.data
643 }
644
645 #[allow(clippy::len_without_is_empty)]
647 pub fn len(&self) -> usize {
648 self.data.len()
649 }
650
651 pub fn into_parts(self) -> (RangeSet<usize>, Vec<u8>) {
653 (self.idx, self.data)
654 }
655
656 #[cfg(test)]
662 pub(crate) fn copy_to(&self, dest: &mut [u8]) {
663 let mut offset = 0;
664 for range in self.idx.iter() {
665 dest[range.clone()].copy_from_slice(&self.data[offset..offset + range.len()]);
666 offset += range.len();
667 }
668 }
669}
670
671#[derive(Debug, thiserror::Error)]
673#[error("invalid subsequence: {0}")]
674pub struct InvalidSubsequence(&'static str);
675
676mod validation {
677 use super::*;
678
679 #[derive(Debug, Deserialize)]
680 pub(super) struct SubsequenceUnchecked {
681 idx: RangeSet<usize>,
682 data: Vec<u8>,
683 }
684
685 impl TryFrom<SubsequenceUnchecked> for Subsequence {
686 type Error = InvalidSubsequence;
687
688 fn try_from(unchecked: SubsequenceUnchecked) -> Result<Self, Self::Error> {
689 Self::new(unchecked.idx, unchecked.data)
690 }
691 }
692
693 #[derive(Debug, thiserror::Error)]
695 #[error("invalid partial transcript: {0}")]
696 pub struct InvalidPartialTranscript(&'static str);
697
698 #[derive(Debug, Deserialize)]
699 #[cfg_attr(test, derive(Serialize))]
700 pub(super) struct PartialTranscriptUnchecked {
701 sent_authed: Vec<u8>,
702 received_authed: Vec<u8>,
703 sent_idx: RangeSet<usize>,
704 recv_idx: RangeSet<usize>,
705 sent_total: usize,
706 recv_total: usize,
707 }
708
709 impl TryFrom<PartialTranscriptUnchecked> for PartialTranscript {
710 type Error = InvalidPartialTranscript;
711
712 fn try_from(unchecked: PartialTranscriptUnchecked) -> Result<Self, Self::Error> {
713 if unchecked.sent_authed.len() != unchecked.sent_idx.len()
714 || unchecked.received_authed.len() != unchecked.recv_idx.len()
715 {
716 return Err(InvalidPartialTranscript(
717 "lengths of index and data don't match",
718 ));
719 }
720
721 if unchecked.sent_idx.end().unwrap_or(0) > unchecked.sent_total
722 || unchecked.recv_idx.end().unwrap_or(0) > unchecked.recv_total
723 {
724 return Err(InvalidPartialTranscript(
725 "ranges are not in bounds of the data",
726 ));
727 }
728
729 Ok(Self {
730 received_authed: unchecked.received_authed,
731 recv_idx: unchecked.recv_idx,
732 recv_total: unchecked.recv_total,
733 sent_authed: unchecked.sent_authed,
734 sent_idx: unchecked.sent_idx,
735 sent_total: unchecked.sent_total,
736 })
737 }
738 }
739
740 #[cfg(test)]
741 mod tests {
742 use rstest::{fixture, rstest};
743
744 use super::*;
745
746 #[fixture]
747 fn partial_transcript() -> PartialTranscriptUnchecked {
748 PartialTranscriptUnchecked {
749 received_authed: vec![1, 2, 3, 11, 12, 13],
750 sent_authed: vec![4, 5, 6, 14, 15, 16],
751 recv_idx: RangeSet::from([1..4, 11..14]),
752 sent_idx: RangeSet::from([4..7, 14..17]),
753 sent_total: 20,
754 recv_total: 20,
755 }
756 }
757
758 #[rstest]
759 fn test_partial_transcript_valid(partial_transcript: PartialTranscriptUnchecked) {
760 let bytes = bincode::serialize(&partial_transcript).unwrap();
761 let transcript: Result<PartialTranscript, Box<bincode::ErrorKind>> =
762 bincode::deserialize(&bytes);
763 assert!(transcript.is_ok());
764 }
765
766 #[rstest]
767 fn test_partial_transcript_invalid_lengths(
770 mut partial_transcript: PartialTranscriptUnchecked,
771 ) {
772 let mut old = partial_transcript.sent_authed;
774 old.extend([1]);
775 partial_transcript.sent_authed = old;
776
777 let bytes = bincode::serialize(&partial_transcript).unwrap();
778 let transcript: Result<PartialTranscript, Box<bincode::ErrorKind>> =
779 bincode::deserialize(&bytes);
780 assert!(transcript.is_err());
781 }
782
783 #[rstest]
784 fn test_partial_transcript_invalid_ranges(
786 mut partial_transcript: PartialTranscriptUnchecked,
787 ) {
788 let end = partial_transcript.sent_idx.iter().next_back().unwrap().end;
790
791 partial_transcript.sent_total = end - 1;
792
793 let bytes = bincode::serialize(&partial_transcript).unwrap();
794 let transcript: Result<PartialTranscript, Box<bincode::ErrorKind>> =
795 bincode::deserialize(&bytes);
796 assert!(transcript.is_err());
797 }
798
799 #[rstest]
800 fn test_partial_transcript_huge_total_does_not_allocate() {
805 let unchecked = PartialTranscriptUnchecked {
806 received_authed: Vec::new(),
807 sent_authed: Vec::new(),
808 recv_idx: RangeSet::default(),
809 sent_idx: RangeSet::default(),
810 sent_total: 1 << 62,
811 recv_total: 0,
812 };
813 let bytes = bincode::serialize(&unchecked).unwrap();
814
815 let transcript: PartialTranscript = bincode::deserialize(&bytes).unwrap();
816 assert_eq!(transcript.len_sent(), 1 << 62);
817
818 assert!(transcript.sent_unsafe(12).is_err());
820 }
821
822 #[rstest]
823 fn test_transcript_proof_huge_total_does_not_allocate() {
826 let unchecked = PartialTranscriptUnchecked {
827 received_authed: Vec::new(),
828 sent_authed: Vec::new(),
829 recv_idx: RangeSet::default(),
830 sent_idx: RangeSet::default(),
831 sent_total: 1 << 62,
832 recv_total: 0,
833 };
834 let bytes = bincode::serialize(&unchecked).unwrap();
835
836 let proof: Result<TranscriptProof, Box<bincode::ErrorKind>> =
839 bincode::deserialize(&bytes);
840 assert!(proof.is_err());
841 }
842 }
843}
844
845#[cfg(test)]
846mod tests {
847 use rstest::{fixture, rstest};
848
849 use super::*;
850
851 fn sent_bytes(partial: &PartialTranscript) -> Vec<u8> {
852 partial.sent_unsafe(partial.len_sent()).unwrap()
853 }
854
855 fn recv_bytes(partial: &PartialTranscript) -> Vec<u8> {
856 partial.received_unsafe(partial.len_received()).unwrap()
857 }
858
859 #[fixture]
860 fn transcript() -> Transcript {
861 Transcript::new(
862 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
863 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
864 )
865 }
866
867 #[fixture]
868 fn partial_transcript() -> PartialTranscript {
869 transcript().to_partial(RangeSet::from([1..4, 6..9]), RangeSet::from([2..5, 7..10]))
870 }
871
872 #[rstest]
873 fn test_transcript_get_subsequence(transcript: Transcript) {
874 let subseq = transcript
875 .get(Direction::Received, &RangeSet::from([0..4, 7..10]))
876 .unwrap();
877 assert_eq!(subseq.data, vec![0, 1, 2, 3, 7, 8, 9]);
878
879 let subseq = transcript
880 .get(Direction::Sent, &RangeSet::from([0..4, 9..12]))
881 .unwrap();
882 assert_eq!(subseq.data, vec![0, 1, 2, 3, 9, 10, 11]);
883
884 let subseq = transcript.get(Direction::Received, &RangeSet::from([0..4, 7..10, 11..13]));
885 assert_eq!(subseq, None);
886
887 let subseq = transcript.get(Direction::Sent, &RangeSet::from([0..4, 7..10, 11..13]));
888 assert_eq!(subseq, None);
889 }
890
891 #[rstest]
892 fn test_partial_transcript_serialization_ok(partial_transcript: PartialTranscript) {
893 let bytes = bincode::serialize(&partial_transcript).unwrap();
894 let deserialized_transcript: PartialTranscript = bincode::deserialize(&bytes).unwrap();
895 assert_eq!(partial_transcript, deserialized_transcript);
896 }
897
898 #[rstest]
899 fn test_transcript_to_partial_success(transcript: Transcript) {
900 let partial = transcript.to_partial(RangeSet::from(0..2), RangeSet::from(3..7));
901 assert_eq!(sent_bytes(&partial), [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
902 assert_eq!(recv_bytes(&partial), [0, 0, 0, 3, 4, 5, 6, 0, 0, 0, 0, 0]);
903 }
904
905 #[rstest]
906 #[should_panic]
907 fn test_transcript_to_partial_failure(transcript: Transcript) {
908 let _ = transcript.to_partial(RangeSet::from(0..14), RangeSet::from(3..7));
909 }
910
911 #[rstest]
912 fn test_partial_transcript_contains(transcript: Transcript) {
913 let partial = transcript.to_partial(RangeSet::from(0..2), RangeSet::from(3..7));
914 assert!(partial.contains(Direction::Sent, &RangeSet::from([0..5, 7..10])));
915 assert!(!partial.contains(Direction::Received, &RangeSet::from([4..6, 7..13])))
916 }
917
918 #[rstest]
919 fn test_partial_transcript_unauthed(transcript: Transcript) {
920 let partial = transcript.to_partial(RangeSet::from(0..2), RangeSet::from(3..7));
921 assert_eq!(partial.sent_unauthed(), RangeSet::from(2..12));
922 assert_eq!(partial.received_unauthed(), RangeSet::from([0..3, 7..12]));
923 }
924
925 #[rstest]
926 fn test_partial_transcript_union_success(transcript: Transcript) {
927 let mut simple_partial = transcript.to_partial(RangeSet::from(0..2), RangeSet::from(3..7));
929
930 let other_simple_partial =
931 transcript.to_partial(RangeSet::from(3..5), RangeSet::from(1..2));
932
933 simple_partial.union_transcript(&other_simple_partial);
934
935 assert_eq!(
936 sent_bytes(&simple_partial),
937 [0, 1, 0, 3, 4, 0, 0, 0, 0, 0, 0, 0]
938 );
939 assert_eq!(
940 recv_bytes(&simple_partial),
941 [0, 1, 0, 3, 4, 5, 6, 0, 0, 0, 0, 0]
942 );
943 assert_eq!(simple_partial.sent_authed(), &RangeSet::from([0..2, 3..5]));
944 assert_eq!(
945 simple_partial.received_authed(),
946 &RangeSet::from([1..2, 3..7])
947 );
948
949 let another_simple_partial =
952 transcript.to_partial(RangeSet::from(1..4), RangeSet::from(6..9));
953
954 simple_partial.union_transcript(&another_simple_partial);
955
956 assert_eq!(
957 sent_bytes(&simple_partial),
958 [0, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0]
959 );
960 assert_eq!(
961 recv_bytes(&simple_partial),
962 [0, 1, 0, 3, 4, 5, 6, 7, 8, 0, 0, 0]
963 );
964 assert_eq!(simple_partial.sent_authed(), &RangeSet::from(0..5));
965 assert_eq!(
966 simple_partial.received_authed(),
967 &RangeSet::from([1..2, 3..9])
968 );
969
970 let mut overlap_partial = transcript.to_partial(RangeSet::from(4..6), RangeSet::from(3..7));
972
973 let other_overlap_partial =
974 transcript.to_partial(RangeSet::from(3..5), RangeSet::from(5..9));
975
976 overlap_partial.union_transcript(&other_overlap_partial);
977
978 assert_eq!(
979 sent_bytes(&overlap_partial),
980 [0, 0, 0, 3, 4, 5, 0, 0, 0, 0, 0, 0]
981 );
982 assert_eq!(
983 recv_bytes(&overlap_partial),
984 [0, 0, 0, 3, 4, 5, 6, 7, 8, 0, 0, 0]
985 );
986 assert_eq!(overlap_partial.sent_authed(), &RangeSet::from([3..5, 4..6]));
987 assert_eq!(
988 overlap_partial.received_authed(),
989 &RangeSet::from([3..7, 5..9])
990 );
991
992 let mut equal_partial = transcript.to_partial(RangeSet::from(4..6), RangeSet::from(3..7));
994
995 let other_equal_partial = transcript.to_partial(RangeSet::from(4..6), RangeSet::from(3..7));
996
997 equal_partial.union_transcript(&other_equal_partial);
998
999 assert_eq!(
1000 sent_bytes(&equal_partial),
1001 [0, 0, 0, 0, 4, 5, 0, 0, 0, 0, 0, 0]
1002 );
1003 assert_eq!(
1004 recv_bytes(&equal_partial),
1005 [0, 0, 0, 3, 4, 5, 6, 0, 0, 0, 0, 0]
1006 );
1007 assert_eq!(equal_partial.sent_authed(), &RangeSet::from(4..6));
1008 assert_eq!(equal_partial.received_authed(), &RangeSet::from(3..7));
1009
1010 let mut subset_partial =
1012 transcript.to_partial(RangeSet::from(4..10), RangeSet::from(3..11));
1013
1014 let other_subset_partial =
1015 transcript.to_partial(RangeSet::from(6..9), RangeSet::from(5..6));
1016
1017 subset_partial.union_transcript(&other_subset_partial);
1018
1019 assert_eq!(
1020 sent_bytes(&subset_partial),
1021 [0, 0, 0, 0, 4, 5, 6, 7, 8, 9, 0, 0]
1022 );
1023 assert_eq!(
1024 recv_bytes(&subset_partial),
1025 [0, 0, 0, 3, 4, 5, 6, 7, 8, 9, 10, 0]
1026 );
1027 assert_eq!(subset_partial.sent_authed(), &RangeSet::from(4..10));
1028 assert_eq!(subset_partial.received_authed(), &RangeSet::from(3..11));
1029 }
1030
1031 #[rstest]
1032 #[should_panic]
1033 fn test_partial_transcript_union_failure(transcript: Transcript) {
1034 let mut partial = transcript.to_partial(RangeSet::from(4..10), RangeSet::from(3..11));
1035
1036 let other_transcript = Transcript::new(
1037 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
1038 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
1039 );
1040
1041 let other_partial = other_transcript.to_partial(RangeSet::from(6..9), RangeSet::from(5..6));
1042
1043 partial.union_transcript(&other_partial);
1044 }
1045
1046 #[rstest]
1047 fn test_partial_transcript_union_subseq_success(transcript: Transcript) {
1048 let mut partial = transcript.to_partial(RangeSet::from(4..10), RangeSet::from(3..11));
1049 let sent_seq =
1050 Subsequence::new(RangeSet::from([0..3, 5..7]), [0, 1, 2, 5, 6].into()).unwrap();
1051 let recv_seq =
1052 Subsequence::new(RangeSet::from([0..4, 5..7]), [0, 1, 2, 3, 5, 6].into()).unwrap();
1053
1054 partial.union_subsequence(Direction::Sent, &sent_seq);
1055 partial.union_subsequence(Direction::Received, &recv_seq);
1056
1057 assert_eq!(sent_bytes(&partial), [0, 1, 2, 0, 4, 5, 6, 7, 8, 9, 0, 0]);
1058 assert_eq!(recv_bytes(&partial), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0]);
1059 assert_eq!(partial.sent_authed(), &RangeSet::from([0..3, 4..10]));
1060 assert_eq!(partial.received_authed(), &RangeSet::from(0..11));
1061
1062 let other_sent_seq = Subsequence::new(RangeSet::from(0..3), [3, 2, 1].into()).unwrap();
1064
1065 partial.union_subsequence(Direction::Sent, &other_sent_seq);
1066 assert_eq!(sent_bytes(&partial), [3, 2, 1, 0, 4, 5, 6, 7, 8, 9, 0, 0]);
1067 assert_eq!(partial.sent_authed(), &RangeSet::from([0..3, 4..10]));
1068 }
1069
1070 #[rstest]
1071 #[should_panic]
1072 fn test_partial_transcript_union_subseq_failure(transcript: Transcript) {
1073 let mut partial = transcript.to_partial(RangeSet::from(4..10), RangeSet::from(3..11));
1074
1075 let sent_seq =
1076 Subsequence::new(RangeSet::from([0..3, 13..15]), [0, 1, 2, 5, 6].into()).unwrap();
1077
1078 partial.union_subsequence(Direction::Sent, &sent_seq);
1079 }
1080
1081 #[rstest]
1082 #[should_panic]
1083 fn test_subsequence_new_invalid_len() {
1084 let _ = Subsequence::new(RangeSet::from([0..3, 5..8]), [0, 1, 2, 5, 6].into()).unwrap();
1085 }
1086
1087 #[rstest]
1088 #[should_panic]
1089 fn test_subsequence_copy_to_invalid_len() {
1090 let seq = Subsequence::new(RangeSet::from([0..3, 5..7]), [0, 1, 2, 5, 6].into()).unwrap();
1091
1092 let mut data: [u8; 3] = [0, 1, 2];
1093 seq.copy_to(&mut data);
1094 }
1095
1096 #[rstest]
1097 fn test_compressed_union(transcript: Transcript) {
1098 let mut a = transcript.to_partial(RangeSet::from(4..10), RangeSet::default());
1100 let b = transcript.to_partial(RangeSet::from([0..3, 5..9]), RangeSet::default());
1101
1102 a.union_transcript(&b);
1103
1104 assert_eq!(a.sent_authed(), &RangeSet::from([0..3, 4..10]));
1106 assert_eq!(a.sent_authed_bytes(), &[0, 1, 2, 4, 5, 6, 7, 8, 9]);
1107 }
1108
1109 #[rstest]
1110 fn test_compressed_union_precedence() {
1111 let mut a = PartialTranscript {
1114 sent_authed: vec![9, 9],
1115 received_authed: Vec::new(),
1116 sent_idx: RangeSet::from(0..2),
1117 recv_idx: RangeSet::default(),
1118 sent_total: 4,
1119 recv_total: 0,
1120 };
1121 let b = PartialTranscript {
1122 sent_authed: vec![1, 1, 1],
1123 received_authed: Vec::new(),
1124 sent_idx: RangeSet::from(1..4),
1125 recv_idx: RangeSet::default(),
1126 sent_total: 4,
1127 recv_total: 0,
1128 };
1129
1130 a.union_transcript(&b);
1131
1132 assert_eq!(a.sent_authed(), &RangeSet::from(0..4));
1134 assert_eq!(a.sent_authed_bytes(), &[9, 9, 1, 1]);
1135 }
1136
1137 #[rstest]
1138 fn test_compressed_union_subsequence(transcript: Transcript) {
1139 let mut compressed = transcript.to_partial(RangeSet::from(4..10), RangeSet::from(3..11));
1140
1141 let sent_seq =
1142 Subsequence::new(RangeSet::from([0..3, 5..7]), [0, 1, 2, 5, 6].into()).unwrap();
1143 let recv_seq =
1144 Subsequence::new(RangeSet::from([0..4, 5..7]), [0, 1, 2, 3, 5, 6].into()).unwrap();
1145
1146 compressed.union_subsequence(Direction::Sent, &sent_seq);
1147 compressed.union_subsequence(Direction::Received, &recv_seq);
1148
1149 assert_eq!(compressed.sent_authed(), &RangeSet::from([0..3, 4..10]));
1150 assert_eq!(compressed.sent_authed_bytes(), &[0, 1, 2, 4, 5, 6, 7, 8, 9]);
1151 assert_eq!(compressed.received_authed(), &RangeSet::from(0..11));
1152 assert_eq!(
1153 compressed.received_authed_bytes(),
1154 &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
1155 );
1156
1157 let other_sent_seq = Subsequence::new(RangeSet::from(0..3), [3, 2, 1].into()).unwrap();
1159 compressed.union_subsequence(Direction::Sent, &other_sent_seq);
1160
1161 assert_eq!(compressed.sent_authed(), &RangeSet::from([0..3, 4..10]));
1162 assert_eq!(compressed.sent_authed_bytes(), &[3, 2, 1, 4, 5, 6, 7, 8, 9]);
1163 }
1164
1165 #[rstest]
1166 #[should_panic]
1167 fn test_compressed_union_subsequence_out_of_bounds(transcript: Transcript) {
1168 let mut compressed = transcript.to_partial(RangeSet::from(4..10), RangeSet::from(3..11));
1169
1170 let sent_seq =
1171 Subsequence::new(RangeSet::from([0..3, 13..15]), [0, 1, 2, 5, 6].into()).unwrap();
1172
1173 compressed.union_subsequence(Direction::Sent, &sent_seq);
1174 }
1175
1176 #[rstest]
1177 fn test_compressed_locate(transcript: Transcript) {
1178 let compressed = transcript.to_partial(RangeSet::from([1..4, 6..9]), RangeSet::default());
1179
1180 assert_eq!(
1182 compressed.locate(Direction::Sent, &(2..4)),
1183 Some([2u8, 3].as_slice())
1184 );
1185 assert_eq!(compressed.locate(Direction::Sent, &(3..7)), None);
1187 assert_eq!(compressed.locate(Direction::Sent, &(0..2)), None);
1189 assert_eq!(compressed.locate(Direction::Sent, &(9..12)), None);
1191 }
1192
1193 #[rstest]
1194 fn test_compressed_sent_unsafe(transcript: Transcript) {
1195 let compressed = transcript.to_partial(RangeSet::from(4..8), RangeSet::from(3..5));
1196
1197 let sent = compressed.sent_unsafe(12).unwrap();
1198 assert_eq!(sent, [0, 0, 0, 0, 4, 5, 6, 7, 0, 0, 0, 0]);
1199 assert_eq!(sent.len(), 12);
1200
1201 let received = compressed.received_unsafe(12).unwrap();
1202 assert_eq!(received, [0, 0, 0, 3, 4, 0, 0, 0, 0, 0, 0, 0]);
1203
1204 assert!(compressed.sent_unsafe(11).is_err());
1206 assert!(compressed.sent_unsafe(1 << 62).is_err());
1207 }
1208
1209 #[rstest]
1210 fn test_materialize_range_fills_gaps(transcript: Transcript) {
1211 let compressed = transcript.to_partial(RangeSet::from([1..3, 6..8]), RangeSet::default());
1212
1213 assert_eq!(
1215 compressed.materialize_range(Direction::Sent, &(0..9)),
1216 [0, 1, 2, 0, 0, 0, 6, 7, 0]
1217 );
1218 assert_eq!(
1220 compressed.materialize_range(Direction::Sent, &(3..6)),
1221 [0, 0, 0]
1222 );
1223 }
1224}