1mod commit;
22pub mod encoding;
23pub mod hash;
24mod proof;
25mod tls;
26
27use std::{fmt, ops::Range};
28
29use rangeset::{Difference, IndexRanges, RangeSet, Subset, ToRangeSet, Union, UnionMut};
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};
42
43#[derive(Clone, Serialize, Deserialize)]
46pub struct Transcript {
47 sent: Vec<u8>,
49 received: Vec<u8>,
51}
52
53opaque_debug::implement!(Transcript);
54
55impl Transcript {
56 pub fn new(sent: impl Into<Vec<u8>>, received: impl Into<Vec<u8>>) -> Self {
58 Self {
59 sent: sent.into(),
60 received: received.into(),
61 }
62 }
63
64 pub fn sent(&self) -> &[u8] {
66 &self.sent
67 }
68
69 pub fn received(&self) -> &[u8] {
71 &self.received
72 }
73
74 #[allow(clippy::len_without_is_empty)]
76 pub fn len(&self) -> (usize, usize) {
77 (self.sent.len(), self.received.len())
78 }
79
80 pub(crate) fn len_of_direction(&self, direction: Direction) -> usize {
82 match direction {
83 Direction::Sent => self.sent.len(),
84 Direction::Received => self.received.len(),
85 }
86 }
87
88 pub fn length(&self) -> TranscriptLength {
90 TranscriptLength {
91 sent: self.sent.len() as u32,
92 received: self.received.len() as u32,
93 }
94 }
95
96 pub fn get(&self, direction: Direction, idx: &Idx) -> Option<Subsequence> {
99 let data = match direction {
100 Direction::Sent => &self.sent,
101 Direction::Received => &self.received,
102 };
103
104 if idx.end() > data.len() {
105 return None;
106 }
107
108 Some(
109 Subsequence::new(idx.clone(), data.index_ranges(&idx.0))
110 .expect("data is same length as index"),
111 )
112 }
113
114 pub fn to_partial(&self, sent_idx: Idx, recv_idx: Idx) -> PartialTranscript {
125 let mut sent = vec![0; self.sent.len()];
126 let mut received = vec![0; self.received.len()];
127
128 for range in sent_idx.iter_ranges() {
129 sent[range.clone()].copy_from_slice(&self.sent[range]);
130 }
131
132 for range in recv_idx.iter_ranges() {
133 received[range.clone()].copy_from_slice(&self.received[range]);
134 }
135
136 PartialTranscript {
137 sent,
138 received,
139 sent_authed_idx: sent_idx,
140 received_authed_idx: recv_idx,
141 }
142 }
143}
144
145#[derive(Debug, Clone, Serialize, Deserialize)]
150#[serde(try_from = "CompressedPartialTranscript")]
151#[serde(into = "CompressedPartialTranscript")]
152#[cfg_attr(test, derive(PartialEq))]
153pub struct PartialTranscript {
154 sent: Vec<u8>,
156 received: Vec<u8>,
158 sent_authed_idx: Idx,
160 received_authed_idx: Idx,
162}
163
164#[derive(Debug, Clone, Serialize, Deserialize)]
166#[serde(try_from = "validation::CompressedPartialTranscriptUnchecked")]
167pub struct CompressedPartialTranscript {
168 sent_authed: Vec<u8>,
170 received_authed: Vec<u8>,
172 sent_idx: Idx,
174 recv_idx: Idx,
176 sent_total: usize,
178 recv_total: usize,
180}
181
182impl From<PartialTranscript> for CompressedPartialTranscript {
183 fn from(uncompressed: PartialTranscript) -> Self {
184 Self {
185 sent_authed: uncompressed
186 .sent
187 .index_ranges(&uncompressed.sent_authed_idx.0),
188 received_authed: uncompressed
189 .received
190 .index_ranges(&uncompressed.received_authed_idx.0),
191 sent_idx: uncompressed.sent_authed_idx,
192 recv_idx: uncompressed.received_authed_idx,
193 sent_total: uncompressed.sent.len(),
194 recv_total: uncompressed.received.len(),
195 }
196 }
197}
198
199impl From<CompressedPartialTranscript> for PartialTranscript {
200 fn from(compressed: CompressedPartialTranscript) -> Self {
201 let mut sent = vec![0; compressed.sent_total];
202 let mut received = vec![0; compressed.recv_total];
203
204 let mut offset = 0;
205
206 for range in compressed.sent_idx.iter_ranges() {
207 sent[range.clone()]
208 .copy_from_slice(&compressed.sent_authed[offset..offset + range.len()]);
209 offset += range.len();
210 }
211
212 let mut offset = 0;
213
214 for range in compressed.recv_idx.iter_ranges() {
215 received[range.clone()]
216 .copy_from_slice(&compressed.received_authed[offset..offset + range.len()]);
217 offset += range.len();
218 }
219
220 Self {
221 sent,
222 received,
223 sent_authed_idx: compressed.sent_idx,
224 received_authed_idx: compressed.recv_idx,
225 }
226 }
227}
228
229impl PartialTranscript {
230 pub fn new(sent_len: usize, received_len: usize) -> Self {
237 Self {
238 sent: vec![0; sent_len],
239 received: vec![0; received_len],
240 sent_authed_idx: Idx::default(),
241 received_authed_idx: Idx::default(),
242 }
243 }
244
245 pub fn len_sent(&self) -> usize {
247 self.sent.len()
248 }
249
250 pub fn len_received(&self) -> usize {
252 self.received.len()
253 }
254
255 pub fn is_complete(&self) -> bool {
257 self.sent_authed_idx.len() == self.sent.len()
258 && self.received_authed_idx.len() == self.received.len()
259 }
260
261 pub fn contains(&self, direction: Direction, idx: &Idx) -> bool {
263 match direction {
264 Direction::Sent => idx.end() <= self.sent.len(),
265 Direction::Received => idx.end() <= self.received.len(),
266 }
267 }
268
269 pub fn sent_unsafe(&self) -> &[u8] {
277 &self.sent
278 }
279
280 pub fn received_unsafe(&self) -> &[u8] {
288 &self.received
289 }
290
291 pub fn sent_authed(&self) -> &Idx {
293 &self.sent_authed_idx
294 }
295
296 pub fn received_authed(&self) -> &Idx {
298 &self.received_authed_idx
299 }
300
301 pub fn sent_unauthed(&self) -> Idx {
303 Idx(RangeSet::from(0..self.sent.len()).difference(&self.sent_authed_idx.0))
304 }
305
306 pub fn received_unauthed(&self) -> Idx {
308 Idx(RangeSet::from(0..self.received.len()).difference(&self.received_authed_idx.0))
309 }
310
311 pub fn iter(&self, direction: Direction) -> impl Iterator<Item = u8> + '_ {
313 let (data, authed) = match direction {
314 Direction::Sent => (&self.sent, &self.sent_authed_idx),
315 Direction::Received => (&self.received, &self.received_authed_idx),
316 };
317
318 authed.0.iter().map(|i| data[i])
319 }
320
321 pub fn union_transcript(&mut self, other: &PartialTranscript) {
327 assert_eq!(
328 self.sent.len(),
329 other.sent.len(),
330 "sent data are not the same length"
331 );
332 assert_eq!(
333 self.received.len(),
334 other.received.len(),
335 "received data are not the same length"
336 );
337
338 for range in other
339 .sent_authed_idx
340 .0
341 .difference(&self.sent_authed_idx.0)
342 .iter_ranges()
343 {
344 self.sent[range.clone()].copy_from_slice(&other.sent[range]);
345 }
346
347 for range in other
348 .received_authed_idx
349 .0
350 .difference(&self.received_authed_idx.0)
351 .iter_ranges()
352 {
353 self.received[range.clone()].copy_from_slice(&other.received[range]);
354 }
355
356 self.sent_authed_idx = self.sent_authed_idx.union(&other.sent_authed_idx);
357 self.received_authed_idx = self.received_authed_idx.union(&other.received_authed_idx);
358 }
359
360 pub fn union_subsequence(&mut self, direction: Direction, seq: &Subsequence) {
366 match direction {
367 Direction::Sent => {
368 seq.copy_to(&mut self.sent);
369 self.sent_authed_idx = self.sent_authed_idx.union(&seq.idx);
370 }
371 Direction::Received => {
372 seq.copy_to(&mut self.received);
373 self.received_authed_idx = self.received_authed_idx.union(&seq.idx);
374 }
375 }
376 }
377
378 pub fn set_unauthed(&mut self, value: u8) {
384 for range in self.sent_unauthed().iter_ranges() {
385 self.sent[range].fill(value);
386 }
387 for range in self.received_unauthed().iter_ranges() {
388 self.received[range].fill(value);
389 }
390 }
391
392 pub fn set_unauthed_range(&mut self, value: u8, direction: Direction, range: Range<usize>) {
400 match direction {
401 Direction::Sent => {
402 for range in range.difference(&self.sent_authed_idx.0).iter_ranges() {
403 self.sent[range].fill(value);
404 }
405 }
406 Direction::Received => {
407 for range in range.difference(&self.received_authed_idx.0).iter_ranges() {
408 self.received[range].fill(value);
409 }
410 }
411 }
412 }
413}
414
415#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
420pub enum Direction {
421 Sent = 0x00,
423 Received = 0x01,
425}
426
427impl fmt::Display for Direction {
428 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
429 match self {
430 Direction::Sent => write!(f, "sent"),
431 Direction::Received => write!(f, "received"),
432 }
433 }
434}
435
436#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
438pub struct Idx(RangeSet<usize>);
439
440impl Idx {
441 pub fn builder() -> IdxBuilder {
443 IdxBuilder::default()
444 }
445
446 pub fn empty() -> Self {
448 Self(RangeSet::default())
449 }
450
451 pub fn new(ranges: impl Into<RangeSet<usize>>) -> Self {
453 Self(ranges.into())
454 }
455
456 pub fn start(&self) -> usize {
458 self.0.min().unwrap_or_default()
459 }
460
461 pub fn end(&self) -> usize {
463 self.0.end().unwrap_or_default()
464 }
465
466 pub fn iter(&self) -> impl Iterator<Item = usize> + '_ {
468 self.0.iter()
469 }
470
471 pub fn iter_ranges(&self) -> impl Iterator<Item = Range<usize>> + '_ {
473 self.0.iter_ranges()
474 }
475
476 pub fn len(&self) -> usize {
478 self.0.len()
479 }
480
481 pub fn is_empty(&self) -> bool {
483 self.0.is_empty()
484 }
485
486 pub fn count(&self) -> usize {
488 self.0.len_ranges()
489 }
490
491 pub(crate) fn as_range_set(&self) -> &RangeSet<usize> {
492 &self.0
493 }
494
495 pub(crate) fn union(&self, other: &Idx) -> Idx {
497 Idx(self.0.union(&other.0))
498 }
499
500 pub(crate) fn union_mut(&mut self, other: &Idx) {
502 self.0.union_mut(&other.0);
503 }
504
505 pub(crate) fn difference(&self, other: &Idx) -> Idx {
507 Idx(self.0.difference(&other.0))
508 }
509
510 pub(crate) fn is_subset(&self, other: &Idx) -> bool {
512 self.0.is_subset(&other.0)
513 }
514}
515
516impl std::fmt::Display for Idx {
517 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
518 f.write_str("Idx([")?;
519 let count = self.0.len_ranges();
520 for (i, range) in self.0.iter_ranges().enumerate() {
521 write!(f, "{}..{}", range.start, range.end)?;
522 if i < count - 1 {
523 write!(f, ", ")?;
524 }
525 }
526 f.write_str("])")?;
527 Ok(())
528 }
529}
530
531#[derive(Debug, Default)]
533pub struct IdxBuilder(RangeSet<usize>);
534
535impl IdxBuilder {
536 pub fn union(self, ranges: &dyn ToRangeSet<usize>) -> Self {
538 IdxBuilder(self.0.union(&ranges.to_range_set()))
539 }
540
541 pub fn build(self) -> Idx {
543 Idx(self.0)
544 }
545}
546
547#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
549#[serde(try_from = "validation::SubsequenceUnchecked")]
550pub struct Subsequence {
551 idx: Idx,
553 data: Vec<u8>,
555}
556
557impl Subsequence {
558 pub fn new(idx: Idx, data: Vec<u8>) -> Result<Self, InvalidSubsequence> {
560 if idx.len() != data.len() {
561 return Err(InvalidSubsequence(
562 "index length does not match data length",
563 ));
564 }
565
566 Ok(Self { idx, data })
567 }
568
569 pub fn index(&self) -> &Idx {
571 &self.idx
572 }
573
574 pub fn data(&self) -> &[u8] {
576 &self.data
577 }
578
579 #[allow(clippy::len_without_is_empty)]
581 pub fn len(&self) -> usize {
582 self.data.len()
583 }
584
585 pub fn into_parts(self) -> (Idx, Vec<u8>) {
587 (self.idx, self.data)
588 }
589
590 pub(crate) fn copy_to(&self, dest: &mut [u8]) {
596 let mut offset = 0;
597 for range in self.idx.iter_ranges() {
598 dest[range.clone()].copy_from_slice(&self.data[offset..offset + range.len()]);
599 offset += range.len();
600 }
601 }
602}
603
604#[derive(Debug, thiserror::Error)]
606#[error("invalid subsequence: {0}")]
607pub struct InvalidSubsequence(&'static str);
608
609mod validation {
610 use super::*;
611
612 #[derive(Debug, Deserialize)]
613 pub(super) struct SubsequenceUnchecked {
614 idx: Idx,
615 data: Vec<u8>,
616 }
617
618 impl TryFrom<SubsequenceUnchecked> for Subsequence {
619 type Error = InvalidSubsequence;
620
621 fn try_from(unchecked: SubsequenceUnchecked) -> Result<Self, Self::Error> {
622 Self::new(unchecked.idx, unchecked.data)
623 }
624 }
625
626 #[derive(Debug, thiserror::Error)]
628 #[error("invalid compressed partial transcript: {0}")]
629 pub struct InvalidCompressedPartialTranscript(&'static str);
630
631 #[derive(Debug, Deserialize)]
632 #[cfg_attr(test, derive(Serialize))]
633 pub(super) struct CompressedPartialTranscriptUnchecked {
634 sent_authed: Vec<u8>,
635 received_authed: Vec<u8>,
636 sent_idx: Idx,
637 recv_idx: Idx,
638 sent_total: usize,
639 recv_total: usize,
640 }
641
642 impl TryFrom<CompressedPartialTranscriptUnchecked> for CompressedPartialTranscript {
643 type Error = InvalidCompressedPartialTranscript;
644
645 fn try_from(unchecked: CompressedPartialTranscriptUnchecked) -> Result<Self, Self::Error> {
646 if unchecked.sent_authed.len() != unchecked.sent_idx.len()
647 || unchecked.received_authed.len() != unchecked.recv_idx.len()
648 {
649 return Err(InvalidCompressedPartialTranscript(
650 "lengths of index and data don't match",
651 ));
652 }
653
654 if unchecked.sent_idx.end() > unchecked.sent_total
655 || unchecked.recv_idx.end() > unchecked.recv_total
656 {
657 return Err(InvalidCompressedPartialTranscript(
658 "ranges are not in bounds of the data",
659 ));
660 }
661
662 Ok(Self {
663 received_authed: unchecked.received_authed,
664 recv_idx: unchecked.recv_idx,
665 recv_total: unchecked.recv_total,
666 sent_authed: unchecked.sent_authed,
667 sent_idx: unchecked.sent_idx,
668 sent_total: unchecked.sent_total,
669 })
670 }
671 }
672
673 #[cfg(test)]
674 mod tests {
675 use rstest::{fixture, rstest};
676
677 use super::*;
678
679 #[fixture]
680 fn partial_transcript() -> CompressedPartialTranscriptUnchecked {
681 CompressedPartialTranscriptUnchecked {
682 received_authed: vec![1, 2, 3, 11, 12, 13],
683 sent_authed: vec![4, 5, 6, 14, 15, 16],
684 recv_idx: Idx(RangeSet::new(&[1..4, 11..14])),
685 sent_idx: Idx(RangeSet::new(&[4..7, 14..17])),
686 sent_total: 20,
687 recv_total: 20,
688 }
689 }
690
691 #[rstest]
692 fn test_partial_transcript_valid(partial_transcript: CompressedPartialTranscriptUnchecked) {
693 let bytes = bincode::serialize(&partial_transcript).unwrap();
694 let transcript: Result<CompressedPartialTranscript, Box<bincode::ErrorKind>> =
695 bincode::deserialize(&bytes);
696 assert!(transcript.is_ok());
697 }
698
699 #[rstest]
700 fn test_partial_transcript_invalid_lengths(
703 mut partial_transcript: CompressedPartialTranscriptUnchecked,
704 ) {
705 let mut old = partial_transcript.sent_authed;
707 old.extend([1]);
708 partial_transcript.sent_authed = old;
709
710 let bytes = bincode::serialize(&partial_transcript).unwrap();
711 let transcript: Result<CompressedPartialTranscript, Box<bincode::ErrorKind>> =
712 bincode::deserialize(&bytes);
713 assert!(transcript.is_err());
714 }
715
716 #[rstest]
717 fn test_partial_transcript_invalid_ranges(
719 mut partial_transcript: CompressedPartialTranscriptUnchecked,
720 ) {
721 let end = partial_transcript
723 .sent_idx
724 .0
725 .iter_ranges()
726 .next_back()
727 .unwrap()
728 .end;
729
730 partial_transcript.sent_total = end - 1;
731
732 let bytes = bincode::serialize(&partial_transcript).unwrap();
733 let transcript: Result<CompressedPartialTranscript, Box<bincode::ErrorKind>> =
734 bincode::deserialize(&bytes);
735 assert!(transcript.is_err());
736 }
737 }
738}
739
740#[cfg(test)]
741mod tests {
742 use rstest::{fixture, rstest};
743
744 use super::*;
745
746 #[fixture]
747 fn transcript() -> Transcript {
748 Transcript::new(
749 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
750 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
751 )
752 }
753
754 #[fixture]
755 fn partial_transcript() -> PartialTranscript {
756 transcript().to_partial(
757 Idx::new(RangeSet::new(&[1..4, 6..9])),
758 Idx::new(RangeSet::new(&[2..5, 7..10])),
759 )
760 }
761
762 #[rstest]
763 fn test_transcript_get_subsequence(transcript: Transcript) {
764 let subseq = transcript
765 .get(Direction::Received, &Idx(RangeSet::from([0..4, 7..10])))
766 .unwrap();
767 assert_eq!(subseq.data, vec![0, 1, 2, 3, 7, 8, 9]);
768
769 let subseq = transcript
770 .get(Direction::Sent, &Idx(RangeSet::from([0..4, 9..12])))
771 .unwrap();
772 assert_eq!(subseq.data, vec![0, 1, 2, 3, 9, 10, 11]);
773
774 let subseq = transcript.get(
775 Direction::Received,
776 &Idx(RangeSet::from([0..4, 7..10, 11..13])),
777 );
778 assert_eq!(subseq, None);
779
780 let subseq = transcript.get(Direction::Sent, &Idx(RangeSet::from([0..4, 7..10, 11..13])));
781 assert_eq!(subseq, None);
782 }
783
784 #[rstest]
785 fn test_partial_transcript_serialization_ok(partial_transcript: PartialTranscript) {
786 let bytes = bincode::serialize(&partial_transcript).unwrap();
787 let deserialized_transcript: PartialTranscript = bincode::deserialize(&bytes).unwrap();
788 assert_eq!(partial_transcript, deserialized_transcript);
789 }
790
791 #[rstest]
792 fn test_transcript_to_partial_success(transcript: Transcript) {
793 let partial = transcript.to_partial(Idx::new(0..2), Idx::new(3..7));
794 assert_eq!(partial.sent_unsafe(), [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
795 assert_eq!(
796 partial.received_unsafe(),
797 [0, 0, 0, 3, 4, 5, 6, 0, 0, 0, 0, 0]
798 );
799 }
800
801 #[rstest]
802 #[should_panic]
803 fn test_transcript_to_partial_failure(transcript: Transcript) {
804 let _ = transcript.to_partial(Idx::new(0..14), Idx::new(3..7));
805 }
806
807 #[rstest]
808 fn test_partial_transcript_contains(transcript: Transcript) {
809 let partial = transcript.to_partial(Idx::new(0..2), Idx::new(3..7));
810 assert!(partial.contains(Direction::Sent, &Idx::new([0..5, 7..10])));
811 assert!(!partial.contains(Direction::Received, &Idx::new([4..6, 7..13])))
812 }
813
814 #[rstest]
815 fn test_partial_transcript_unauthed(transcript: Transcript) {
816 let partial = transcript.to_partial(Idx::new(0..2), Idx::new(3..7));
817 assert_eq!(partial.sent_unauthed(), Idx::new(2..12));
818 assert_eq!(partial.received_unauthed(), Idx::new([0..3, 7..12]));
819 }
820
821 #[rstest]
822 fn test_partial_transcript_union_success(transcript: Transcript) {
823 let mut simple_partial = transcript.to_partial(Idx::new(0..2), Idx::new(3..7));
825
826 let other_simple_partial = transcript.to_partial(Idx::new(3..5), Idx::new(1..2));
827
828 simple_partial.union_transcript(&other_simple_partial);
829
830 assert_eq!(
831 simple_partial.sent_unsafe(),
832 [0, 1, 0, 3, 4, 0, 0, 0, 0, 0, 0, 0]
833 );
834 assert_eq!(
835 simple_partial.received_unsafe(),
836 [0, 1, 0, 3, 4, 5, 6, 0, 0, 0, 0, 0]
837 );
838 assert_eq!(simple_partial.sent_authed(), &Idx::new([0..2, 3..5]));
839 assert_eq!(simple_partial.received_authed(), &Idx::new([1..2, 3..7]));
840
841 let another_simple_partial = transcript.to_partial(Idx::new(1..4), Idx::new(6..9));
844
845 simple_partial.union_transcript(&another_simple_partial);
846
847 assert_eq!(
848 simple_partial.sent_unsafe(),
849 [0, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0]
850 );
851 assert_eq!(
852 simple_partial.received_unsafe(),
853 [0, 1, 0, 3, 4, 5, 6, 7, 8, 0, 0, 0]
854 );
855 assert_eq!(simple_partial.sent_authed(), &Idx::new(0..5));
856 assert_eq!(simple_partial.received_authed(), &Idx::new([1..2, 3..9]));
857
858 let mut overlap_partial = transcript.to_partial(Idx::new(4..6), Idx::new(3..7));
860
861 let other_overlap_partial = transcript.to_partial(Idx::new(3..5), Idx::new(5..9));
862
863 overlap_partial.union_transcript(&other_overlap_partial);
864
865 assert_eq!(
866 overlap_partial.sent_unsafe(),
867 [0, 0, 0, 3, 4, 5, 0, 0, 0, 0, 0, 0]
868 );
869 assert_eq!(
870 overlap_partial.received_unsafe(),
871 [0, 0, 0, 3, 4, 5, 6, 7, 8, 0, 0, 0]
872 );
873 assert_eq!(overlap_partial.sent_authed(), &Idx::new([3..5, 4..6]));
874 assert_eq!(overlap_partial.received_authed(), &Idx::new([3..7, 5..9]));
875
876 let mut equal_partial = transcript.to_partial(Idx::new(4..6), Idx::new(3..7));
878
879 let other_equal_partial = transcript.to_partial(Idx::new(4..6), Idx::new(3..7));
880
881 equal_partial.union_transcript(&other_equal_partial);
882
883 assert_eq!(
884 equal_partial.sent_unsafe(),
885 [0, 0, 0, 0, 4, 5, 0, 0, 0, 0, 0, 0]
886 );
887 assert_eq!(
888 equal_partial.received_unsafe(),
889 [0, 0, 0, 3, 4, 5, 6, 0, 0, 0, 0, 0]
890 );
891 assert_eq!(equal_partial.sent_authed(), &Idx::new(4..6));
892 assert_eq!(equal_partial.received_authed(), &Idx::new(3..7));
893
894 let mut subset_partial = transcript.to_partial(Idx::new(4..10), Idx::new(3..11));
896
897 let other_subset_partial = transcript.to_partial(Idx::new(6..9), Idx::new(5..6));
898
899 subset_partial.union_transcript(&other_subset_partial);
900
901 assert_eq!(
902 subset_partial.sent_unsafe(),
903 [0, 0, 0, 0, 4, 5, 6, 7, 8, 9, 0, 0]
904 );
905 assert_eq!(
906 subset_partial.received_unsafe(),
907 [0, 0, 0, 3, 4, 5, 6, 7, 8, 9, 10, 0]
908 );
909 assert_eq!(subset_partial.sent_authed(), &Idx::new(4..10));
910 assert_eq!(subset_partial.received_authed(), &Idx::new(3..11));
911 }
912
913 #[rstest]
914 #[should_panic]
915 fn test_partial_transcript_union_failure(transcript: Transcript) {
916 let mut partial = transcript.to_partial(Idx::new(4..10), Idx::new(3..11));
917
918 let other_transcript = Transcript::new(
919 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
920 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
921 );
922
923 let other_partial = other_transcript.to_partial(Idx::new(6..9), Idx::new(5..6));
924
925 partial.union_transcript(&other_partial);
926 }
927
928 #[rstest]
929 fn test_partial_transcript_union_subseq_success(transcript: Transcript) {
930 let mut partial = transcript.to_partial(Idx::new(4..10), Idx::new(3..11));
931 let sent_seq = Subsequence::new(Idx::new([0..3, 5..7]), [0, 1, 2, 5, 6].into()).unwrap();
932 let recv_seq = Subsequence::new(Idx::new([0..4, 5..7]), [0, 1, 2, 3, 5, 6].into()).unwrap();
933
934 partial.union_subsequence(Direction::Sent, &sent_seq);
935 partial.union_subsequence(Direction::Received, &recv_seq);
936
937 assert_eq!(partial.sent_unsafe(), [0, 1, 2, 0, 4, 5, 6, 7, 8, 9, 0, 0]);
938 assert_eq!(
939 partial.received_unsafe(),
940 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0]
941 );
942 assert_eq!(partial.sent_authed(), &Idx::new([0..3, 4..10]));
943 assert_eq!(partial.received_authed(), &Idx::new(0..11));
944
945 let other_sent_seq = Subsequence::new(Idx::new(0..3), [3, 2, 1].into()).unwrap();
947
948 partial.union_subsequence(Direction::Sent, &other_sent_seq);
949 assert_eq!(partial.sent_unsafe(), [3, 2, 1, 0, 4, 5, 6, 7, 8, 9, 0, 0]);
950 assert_eq!(partial.sent_authed(), &Idx::new([0..3, 4..10]));
951 }
952
953 #[rstest]
954 #[should_panic]
955 fn test_partial_transcript_union_subseq_failure(transcript: Transcript) {
956 let mut partial = transcript.to_partial(Idx::new(4..10), Idx::new(3..11));
957
958 let sent_seq = Subsequence::new(Idx::new([0..3, 13..15]), [0, 1, 2, 5, 6].into()).unwrap();
959
960 partial.union_subsequence(Direction::Sent, &sent_seq);
961 }
962
963 #[rstest]
964 fn test_partial_transcript_set_unauthed_range(transcript: Transcript) {
965 let mut partial = transcript.to_partial(Idx::new(4..10), Idx::new(3..7));
966
967 partial.set_unauthed_range(7, Direction::Sent, 2..5);
968 partial.set_unauthed_range(5, Direction::Sent, 0..2);
969 partial.set_unauthed_range(3, Direction::Received, 4..6);
970 partial.set_unauthed_range(1, Direction::Received, 3..7);
971
972 assert_eq!(partial.sent_unsafe(), [5, 5, 7, 7, 4, 5, 6, 7, 8, 9, 0, 0]);
973 assert_eq!(
974 partial.received_unsafe(),
975 [0, 0, 0, 3, 4, 5, 6, 0, 0, 0, 0, 0]
976 );
977 }
978
979 #[rstest]
980 #[should_panic]
981 fn test_subsequence_new_invalid_len() {
982 let _ = Subsequence::new(Idx::new([0..3, 5..8]), [0, 1, 2, 5, 6].into()).unwrap();
983 }
984
985 #[rstest]
986 #[should_panic]
987 fn test_subsequence_copy_to_invalid_len() {
988 let seq = Subsequence::new(Idx::new([0..3, 5..7]), [0, 1, 2, 5, 6].into()).unwrap();
989
990 let mut data: [u8; 3] = [0, 1, 2];
991 seq.copy_to(&mut data);
992 }
993}