1mod commit;
35#[doc(hidden)]
36pub mod encoding;
37pub(crate) mod hash;
38mod proof;
39
40use std::{fmt, ops::Range};
41
42use rangeset::{Difference, IndexRanges, RangeSet, Subset, ToRangeSet, Union, UnionMut};
43use serde::{Deserialize, Serialize};
44
45use crate::connection::TranscriptLength;
46
47pub use commit::{
48 TranscriptCommitConfig, TranscriptCommitConfigBuilder, TranscriptCommitConfigBuilderError,
49 TranscriptCommitmentKind,
50};
51pub use proof::{
52 TranscriptProof, TranscriptProofBuilder, TranscriptProofBuilderError, TranscriptProofError,
53};
54
55#[derive(Clone, Serialize, Deserialize)]
58pub struct Transcript {
59 sent: Vec<u8>,
61 received: Vec<u8>,
63}
64
65opaque_debug::implement!(Transcript);
66
67impl Transcript {
68 pub fn new(sent: impl Into<Vec<u8>>, received: impl Into<Vec<u8>>) -> Self {
70 Self {
71 sent: sent.into(),
72 received: received.into(),
73 }
74 }
75
76 pub fn sent(&self) -> &[u8] {
78 &self.sent
79 }
80
81 pub fn received(&self) -> &[u8] {
83 &self.received
84 }
85
86 #[allow(clippy::len_without_is_empty)]
88 pub fn len(&self) -> (usize, usize) {
89 (self.sent.len(), self.received.len())
90 }
91
92 pub(crate) fn len_of_direction(&self, direction: Direction) -> usize {
94 match direction {
95 Direction::Sent => self.sent.len(),
96 Direction::Received => self.received.len(),
97 }
98 }
99
100 pub fn length(&self) -> TranscriptLength {
102 TranscriptLength {
103 sent: self.sent.len() as u32,
104 received: self.received.len() as u32,
105 }
106 }
107
108 pub fn get(&self, direction: Direction, idx: &Idx) -> Option<Subsequence> {
111 let data = match direction {
112 Direction::Sent => &self.sent,
113 Direction::Received => &self.received,
114 };
115
116 if idx.end() > data.len() {
117 return None;
118 }
119
120 Some(
121 Subsequence::new(idx.clone(), data.index_ranges(&idx.0))
122 .expect("data is same length as index"),
123 )
124 }
125
126 pub fn to_partial(&self, sent_idx: Idx, recv_idx: Idx) -> PartialTranscript {
137 let mut sent = vec![0; self.sent.len()];
138 let mut received = vec![0; self.received.len()];
139
140 for range in sent_idx.iter_ranges() {
141 sent[range.clone()].copy_from_slice(&self.sent[range]);
142 }
143
144 for range in recv_idx.iter_ranges() {
145 received[range.clone()].copy_from_slice(&self.received[range]);
146 }
147
148 PartialTranscript {
149 sent,
150 received,
151 sent_authed_idx: sent_idx,
152 received_authed_idx: recv_idx,
153 }
154 }
155}
156
157#[derive(Debug, Clone, Serialize, Deserialize)]
162#[serde(try_from = "CompressedPartialTranscript")]
163#[serde(into = "CompressedPartialTranscript")]
164#[cfg_attr(test, derive(PartialEq))]
165pub struct PartialTranscript {
166 sent: Vec<u8>,
168 received: Vec<u8>,
170 sent_authed_idx: Idx,
172 received_authed_idx: Idx,
174}
175
176#[derive(Debug, Clone, Serialize, Deserialize)]
178#[serde(try_from = "validation::CompressedPartialTranscriptUnchecked")]
179pub struct CompressedPartialTranscript {
180 sent_authed: Vec<u8>,
182 received_authed: Vec<u8>,
184 sent_idx: Idx,
186 recv_idx: Idx,
188 sent_total: usize,
190 recv_total: usize,
192}
193
194impl From<PartialTranscript> for CompressedPartialTranscript {
195 fn from(uncompressed: PartialTranscript) -> Self {
196 Self {
197 sent_authed: uncompressed
198 .sent
199 .index_ranges(&uncompressed.sent_authed_idx.0),
200 received_authed: uncompressed
201 .received
202 .index_ranges(&uncompressed.received_authed_idx.0),
203 sent_idx: uncompressed.sent_authed_idx,
204 recv_idx: uncompressed.received_authed_idx,
205 sent_total: uncompressed.sent.len(),
206 recv_total: uncompressed.received.len(),
207 }
208 }
209}
210
211impl From<CompressedPartialTranscript> for PartialTranscript {
212 fn from(compressed: CompressedPartialTranscript) -> Self {
213 let mut sent = vec![0; compressed.sent_total];
214 let mut received = vec![0; compressed.recv_total];
215
216 let mut offset = 0;
217
218 for range in compressed.sent_idx.iter_ranges() {
219 sent[range.clone()]
220 .copy_from_slice(&compressed.sent_authed[offset..offset + range.len()]);
221 offset += range.len();
222 }
223
224 let mut offset = 0;
225
226 for range in compressed.recv_idx.iter_ranges() {
227 received[range.clone()]
228 .copy_from_slice(&compressed.received_authed[offset..offset + range.len()]);
229 offset += range.len();
230 }
231
232 Self {
233 sent,
234 received,
235 sent_authed_idx: compressed.sent_idx,
236 received_authed_idx: compressed.recv_idx,
237 }
238 }
239}
240
241impl PartialTranscript {
242 pub fn new(sent_len: usize, received_len: usize) -> Self {
249 Self {
250 sent: vec![0; sent_len],
251 received: vec![0; received_len],
252 sent_authed_idx: Idx::default(),
253 received_authed_idx: Idx::default(),
254 }
255 }
256
257 pub fn len_sent(&self) -> usize {
259 self.sent.len()
260 }
261
262 pub fn len_received(&self) -> usize {
264 self.received.len()
265 }
266
267 pub fn is_complete(&self) -> bool {
269 self.sent_authed_idx.len() == self.sent.len()
270 && self.received_authed_idx.len() == self.received.len()
271 }
272
273 pub fn contains(&self, direction: Direction, idx: &Idx) -> bool {
275 match direction {
276 Direction::Sent => idx.end() <= self.sent.len(),
277 Direction::Received => idx.end() <= self.received.len(),
278 }
279 }
280
281 pub fn sent_unsafe(&self) -> &[u8] {
289 &self.sent
290 }
291
292 pub fn received_unsafe(&self) -> &[u8] {
300 &self.received
301 }
302
303 pub fn sent_authed(&self) -> &Idx {
305 &self.sent_authed_idx
306 }
307
308 pub fn received_authed(&self) -> &Idx {
310 &self.received_authed_idx
311 }
312
313 pub fn sent_unauthed(&self) -> Idx {
315 Idx(RangeSet::from(0..self.sent.len()).difference(&self.sent_authed_idx.0))
316 }
317
318 pub fn received_unauthed(&self) -> Idx {
320 Idx(RangeSet::from(0..self.received.len()).difference(&self.received_authed_idx.0))
321 }
322
323 pub fn iter(&self, direction: Direction) -> impl Iterator<Item = u8> + '_ {
325 let (data, authed) = match direction {
326 Direction::Sent => (&self.sent, &self.sent_authed_idx),
327 Direction::Received => (&self.received, &self.received_authed_idx),
328 };
329
330 authed.0.iter().map(|i| data[i])
331 }
332
333 pub fn union_transcript(&mut self, other: &PartialTranscript) {
339 assert_eq!(
340 self.sent.len(),
341 other.sent.len(),
342 "sent data are not the same length"
343 );
344 assert_eq!(
345 self.received.len(),
346 other.received.len(),
347 "received data are not the same length"
348 );
349
350 for range in other
351 .sent_authed_idx
352 .0
353 .difference(&self.sent_authed_idx.0)
354 .iter_ranges()
355 {
356 self.sent[range.clone()].copy_from_slice(&other.sent[range]);
357 }
358
359 for range in other
360 .received_authed_idx
361 .0
362 .difference(&self.received_authed_idx.0)
363 .iter_ranges()
364 {
365 self.received[range.clone()].copy_from_slice(&other.received[range]);
366 }
367
368 self.sent_authed_idx = self.sent_authed_idx.union(&other.sent_authed_idx);
369 self.received_authed_idx = self.received_authed_idx.union(&other.received_authed_idx);
370 }
371
372 pub fn union_subsequence(&mut self, direction: Direction, seq: &Subsequence) {
378 match direction {
379 Direction::Sent => {
380 seq.copy_to(&mut self.sent);
381 self.sent_authed_idx = self.sent_authed_idx.union(&seq.idx);
382 }
383 Direction::Received => {
384 seq.copy_to(&mut self.received);
385 self.received_authed_idx = self.received_authed_idx.union(&seq.idx);
386 }
387 }
388 }
389
390 pub fn set_unauthed(&mut self, value: u8) {
396 for range in self.sent_unauthed().iter_ranges() {
397 self.sent[range].fill(value);
398 }
399 for range in self.received_unauthed().iter_ranges() {
400 self.received[range].fill(value);
401 }
402 }
403
404 pub fn set_unauthed_range(&mut self, value: u8, direction: Direction, range: Range<usize>) {
412 match direction {
413 Direction::Sent => {
414 for range in range.difference(&self.sent_authed_idx.0).iter_ranges() {
415 self.sent[range].fill(value);
416 }
417 }
418 Direction::Received => {
419 for range in range.difference(&self.received_authed_idx.0).iter_ranges() {
420 self.received[range].fill(value);
421 }
422 }
423 }
424 }
425}
426
427#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
432pub enum Direction {
433 Sent = 0x00,
435 Received = 0x01,
437}
438
439impl fmt::Display for Direction {
440 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
441 match self {
442 Direction::Sent => write!(f, "sent"),
443 Direction::Received => write!(f, "received"),
444 }
445 }
446}
447
448#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
450pub struct Idx(RangeSet<usize>);
451
452impl Idx {
453 pub fn builder() -> IdxBuilder {
455 IdxBuilder::default()
456 }
457
458 pub fn empty() -> Self {
460 Self(RangeSet::default())
461 }
462
463 pub fn new(ranges: impl Into<RangeSet<usize>>) -> Self {
465 Self(ranges.into())
466 }
467
468 pub fn start(&self) -> usize {
470 self.0.min().unwrap_or_default()
471 }
472
473 pub fn end(&self) -> usize {
475 self.0.end().unwrap_or_default()
476 }
477
478 pub fn iter(&self) -> impl Iterator<Item = usize> + '_ {
480 self.0.iter()
481 }
482
483 pub fn iter_ranges(&self) -> impl Iterator<Item = Range<usize>> + '_ {
485 self.0.iter_ranges()
486 }
487
488 pub fn len(&self) -> usize {
490 self.0.len()
491 }
492
493 pub fn is_empty(&self) -> bool {
495 self.0.is_empty()
496 }
497
498 pub fn count(&self) -> usize {
500 self.0.len_ranges()
501 }
502
503 pub(crate) fn as_range_set(&self) -> &RangeSet<usize> {
504 &self.0
505 }
506
507 pub(crate) fn union(&self, other: &Idx) -> Idx {
509 Idx(self.0.union(&other.0))
510 }
511
512 pub(crate) fn union_mut(&mut self, other: &Idx) {
514 self.0.union_mut(&other.0);
515 }
516
517 pub(crate) fn difference(&self, other: &Idx) -> Idx {
519 Idx(self.0.difference(&other.0))
520 }
521
522 pub(crate) fn is_subset(&self, other: &Idx) -> bool {
524 self.0.is_subset(&other.0)
525 }
526}
527
528impl std::fmt::Display for Idx {
529 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
530 f.write_str("Idx([")?;
531 let count = self.0.len_ranges();
532 for (i, range) in self.0.iter_ranges().enumerate() {
533 write!(f, "{}..{}", range.start, range.end)?;
534 if i < count - 1 {
535 write!(f, ", ")?;
536 }
537 }
538 f.write_str("])")?;
539 Ok(())
540 }
541}
542
543#[derive(Debug, Default)]
545pub struct IdxBuilder(RangeSet<usize>);
546
547impl IdxBuilder {
548 pub fn union(self, ranges: &dyn ToRangeSet<usize>) -> Self {
550 IdxBuilder(self.0.union(&ranges.to_range_set()))
551 }
552
553 pub fn build(self) -> Idx {
555 Idx(self.0)
556 }
557}
558
559#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
561#[serde(try_from = "validation::SubsequenceUnchecked")]
562pub struct Subsequence {
563 idx: Idx,
565 data: Vec<u8>,
567}
568
569impl Subsequence {
570 pub fn new(idx: Idx, data: Vec<u8>) -> Result<Self, InvalidSubsequence> {
572 if idx.len() != data.len() {
573 return Err(InvalidSubsequence(
574 "index length does not match data length",
575 ));
576 }
577
578 Ok(Self { idx, data })
579 }
580
581 pub fn index(&self) -> &Idx {
583 &self.idx
584 }
585
586 pub fn data(&self) -> &[u8] {
588 &self.data
589 }
590
591 #[allow(clippy::len_without_is_empty)]
593 pub fn len(&self) -> usize {
594 self.data.len()
595 }
596
597 pub fn into_parts(self) -> (Idx, Vec<u8>) {
599 (self.idx, self.data)
600 }
601
602 pub(crate) fn copy_to(&self, dest: &mut [u8]) {
608 let mut offset = 0;
609 for range in self.idx.iter_ranges() {
610 dest[range.clone()].copy_from_slice(&self.data[offset..offset + range.len()]);
611 offset += range.len();
612 }
613 }
614}
615
616#[derive(Debug, thiserror::Error)]
618#[error("invalid subsequence: {0}")]
619pub struct InvalidSubsequence(&'static str);
620
621mod validation {
622 use super::*;
623
624 #[derive(Debug, Deserialize)]
625 pub(super) struct SubsequenceUnchecked {
626 idx: Idx,
627 data: Vec<u8>,
628 }
629
630 impl TryFrom<SubsequenceUnchecked> for Subsequence {
631 type Error = InvalidSubsequence;
632
633 fn try_from(unchecked: SubsequenceUnchecked) -> Result<Self, Self::Error> {
634 Self::new(unchecked.idx, unchecked.data)
635 }
636 }
637
638 #[derive(Debug, thiserror::Error)]
640 #[error("invalid compressed partial transcript: {0}")]
641 pub struct InvalidCompressedPartialTranscript(&'static str);
642
643 #[derive(Debug, Deserialize)]
644 #[cfg_attr(test, derive(Serialize))]
645 pub(super) struct CompressedPartialTranscriptUnchecked {
646 sent_authed: Vec<u8>,
647 received_authed: Vec<u8>,
648 sent_idx: Idx,
649 recv_idx: Idx,
650 sent_total: usize,
651 recv_total: usize,
652 }
653
654 impl TryFrom<CompressedPartialTranscriptUnchecked> for CompressedPartialTranscript {
655 type Error = InvalidCompressedPartialTranscript;
656
657 fn try_from(unchecked: CompressedPartialTranscriptUnchecked) -> Result<Self, Self::Error> {
658 if unchecked.sent_authed.len() != unchecked.sent_idx.len()
659 || unchecked.received_authed.len() != unchecked.recv_idx.len()
660 {
661 return Err(InvalidCompressedPartialTranscript(
662 "lengths of index and data don't match",
663 ));
664 }
665
666 if unchecked.sent_idx.end() > unchecked.sent_total
667 || unchecked.recv_idx.end() > unchecked.recv_total
668 {
669 return Err(InvalidCompressedPartialTranscript(
670 "ranges are not in bounds of the data",
671 ));
672 }
673
674 Ok(Self {
675 received_authed: unchecked.received_authed,
676 recv_idx: unchecked.recv_idx,
677 recv_total: unchecked.recv_total,
678 sent_authed: unchecked.sent_authed,
679 sent_idx: unchecked.sent_idx,
680 sent_total: unchecked.sent_total,
681 })
682 }
683 }
684
685 #[cfg(test)]
686 mod tests {
687 use rstest::{fixture, rstest};
688
689 use super::*;
690
691 #[fixture]
692 fn partial_transcript() -> CompressedPartialTranscriptUnchecked {
693 CompressedPartialTranscriptUnchecked {
694 received_authed: vec![1, 2, 3, 11, 12, 13],
695 sent_authed: vec![4, 5, 6, 14, 15, 16],
696 recv_idx: Idx(RangeSet::new(&[1..4, 11..14])),
697 sent_idx: Idx(RangeSet::new(&[4..7, 14..17])),
698 sent_total: 20,
699 recv_total: 20,
700 }
701 }
702
703 #[rstest]
704 fn test_partial_transcript_valid(partial_transcript: CompressedPartialTranscriptUnchecked) {
705 let bytes = bincode::serialize(&partial_transcript).unwrap();
706 let transcript: Result<CompressedPartialTranscript, Box<bincode::ErrorKind>> =
707 bincode::deserialize(&bytes);
708 assert!(transcript.is_ok());
709 }
710
711 #[rstest]
712 fn test_partial_transcript_invalid_lengths(
715 mut partial_transcript: CompressedPartialTranscriptUnchecked,
716 ) {
717 let mut old = partial_transcript.sent_authed;
719 old.extend([1]);
720 partial_transcript.sent_authed = old;
721
722 let bytes = bincode::serialize(&partial_transcript).unwrap();
723 let transcript: Result<CompressedPartialTranscript, Box<bincode::ErrorKind>> =
724 bincode::deserialize(&bytes);
725 assert!(transcript.is_err());
726 }
727
728 #[rstest]
729 fn test_partial_transcript_invalid_ranges(
731 mut partial_transcript: CompressedPartialTranscriptUnchecked,
732 ) {
733 let end = partial_transcript
735 .sent_idx
736 .0
737 .iter_ranges()
738 .next_back()
739 .unwrap()
740 .end;
741
742 partial_transcript.sent_total = end - 1;
743
744 let bytes = bincode::serialize(&partial_transcript).unwrap();
745 let transcript: Result<CompressedPartialTranscript, Box<bincode::ErrorKind>> =
746 bincode::deserialize(&bytes);
747 assert!(transcript.is_err());
748 }
749 }
750}
751
752#[cfg(test)]
753mod tests {
754 use rstest::{fixture, rstest};
755
756 use super::*;
757
758 #[fixture]
759 fn transcript() -> Transcript {
760 Transcript::new(
761 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
762 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
763 )
764 }
765
766 #[fixture]
767 fn partial_transcript() -> PartialTranscript {
768 transcript().to_partial(
769 Idx::new(RangeSet::new(&[1..4, 6..9])),
770 Idx::new(RangeSet::new(&[2..5, 7..10])),
771 )
772 }
773
774 #[rstest]
775 fn test_transcript_get_subsequence(transcript: Transcript) {
776 let subseq = transcript
777 .get(Direction::Received, &Idx(RangeSet::from([0..4, 7..10])))
778 .unwrap();
779 assert_eq!(subseq.data, vec![0, 1, 2, 3, 7, 8, 9]);
780
781 let subseq = transcript
782 .get(Direction::Sent, &Idx(RangeSet::from([0..4, 9..12])))
783 .unwrap();
784 assert_eq!(subseq.data, vec![0, 1, 2, 3, 9, 10, 11]);
785
786 let subseq = transcript.get(
787 Direction::Received,
788 &Idx(RangeSet::from([0..4, 7..10, 11..13])),
789 );
790 assert_eq!(subseq, None);
791
792 let subseq = transcript.get(Direction::Sent, &Idx(RangeSet::from([0..4, 7..10, 11..13])));
793 assert_eq!(subseq, None);
794 }
795
796 #[rstest]
797 fn test_partial_transcript_serialization_ok(partial_transcript: PartialTranscript) {
798 let bytes = bincode::serialize(&partial_transcript).unwrap();
799 let deserialized_transcript: PartialTranscript = bincode::deserialize(&bytes).unwrap();
800 assert_eq!(partial_transcript, deserialized_transcript);
801 }
802
803 #[rstest]
804 fn test_transcript_to_partial_success(transcript: Transcript) {
805 let partial = transcript.to_partial(Idx::new(0..2), Idx::new(3..7));
806 assert_eq!(partial.sent_unsafe(), [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
807 assert_eq!(
808 partial.received_unsafe(),
809 [0, 0, 0, 3, 4, 5, 6, 0, 0, 0, 0, 0]
810 );
811 }
812
813 #[rstest]
814 #[should_panic]
815 fn test_transcript_to_partial_failure(transcript: Transcript) {
816 let _ = transcript.to_partial(Idx::new(0..14), Idx::new(3..7));
817 }
818
819 #[rstest]
820 fn test_partial_transcript_contains(transcript: Transcript) {
821 let partial = transcript.to_partial(Idx::new(0..2), Idx::new(3..7));
822 assert!(partial.contains(Direction::Sent, &Idx::new([0..5, 7..10])));
823 assert!(!partial.contains(Direction::Received, &Idx::new([4..6, 7..13])))
824 }
825
826 #[rstest]
827 fn test_partial_transcript_unauthed(transcript: Transcript) {
828 let partial = transcript.to_partial(Idx::new(0..2), Idx::new(3..7));
829 assert_eq!(partial.sent_unauthed(), Idx::new(2..12));
830 assert_eq!(partial.received_unauthed(), Idx::new([0..3, 7..12]));
831 }
832
833 #[rstest]
834 fn test_partial_transcript_union_success(transcript: Transcript) {
835 let mut simple_partial = transcript.to_partial(Idx::new(0..2), Idx::new(3..7));
837
838 let other_simple_partial = transcript.to_partial(Idx::new(3..5), Idx::new(1..2));
839
840 simple_partial.union_transcript(&other_simple_partial);
841
842 assert_eq!(
843 simple_partial.sent_unsafe(),
844 [0, 1, 0, 3, 4, 0, 0, 0, 0, 0, 0, 0]
845 );
846 assert_eq!(
847 simple_partial.received_unsafe(),
848 [0, 1, 0, 3, 4, 5, 6, 0, 0, 0, 0, 0]
849 );
850 assert_eq!(simple_partial.sent_authed(), &Idx::new([0..2, 3..5]));
851 assert_eq!(simple_partial.received_authed(), &Idx::new([1..2, 3..7]));
852
853 let another_simple_partial = transcript.to_partial(Idx::new(1..4), Idx::new(6..9));
856
857 simple_partial.union_transcript(&another_simple_partial);
858
859 assert_eq!(
860 simple_partial.sent_unsafe(),
861 [0, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0]
862 );
863 assert_eq!(
864 simple_partial.received_unsafe(),
865 [0, 1, 0, 3, 4, 5, 6, 7, 8, 0, 0, 0]
866 );
867 assert_eq!(simple_partial.sent_authed(), &Idx::new(0..5));
868 assert_eq!(simple_partial.received_authed(), &Idx::new([1..2, 3..9]));
869
870 let mut overlap_partial = transcript.to_partial(Idx::new(4..6), Idx::new(3..7));
872
873 let other_overlap_partial = transcript.to_partial(Idx::new(3..5), Idx::new(5..9));
874
875 overlap_partial.union_transcript(&other_overlap_partial);
876
877 assert_eq!(
878 overlap_partial.sent_unsafe(),
879 [0, 0, 0, 3, 4, 5, 0, 0, 0, 0, 0, 0]
880 );
881 assert_eq!(
882 overlap_partial.received_unsafe(),
883 [0, 0, 0, 3, 4, 5, 6, 7, 8, 0, 0, 0]
884 );
885 assert_eq!(overlap_partial.sent_authed(), &Idx::new([3..5, 4..6]));
886 assert_eq!(overlap_partial.received_authed(), &Idx::new([3..7, 5..9]));
887
888 let mut equal_partial = transcript.to_partial(Idx::new(4..6), Idx::new(3..7));
890
891 let other_equal_partial = transcript.to_partial(Idx::new(4..6), Idx::new(3..7));
892
893 equal_partial.union_transcript(&other_equal_partial);
894
895 assert_eq!(
896 equal_partial.sent_unsafe(),
897 [0, 0, 0, 0, 4, 5, 0, 0, 0, 0, 0, 0]
898 );
899 assert_eq!(
900 equal_partial.received_unsafe(),
901 [0, 0, 0, 3, 4, 5, 6, 0, 0, 0, 0, 0]
902 );
903 assert_eq!(equal_partial.sent_authed(), &Idx::new(4..6));
904 assert_eq!(equal_partial.received_authed(), &Idx::new(3..7));
905
906 let mut subset_partial = transcript.to_partial(Idx::new(4..10), Idx::new(3..11));
908
909 let other_subset_partial = transcript.to_partial(Idx::new(6..9), Idx::new(5..6));
910
911 subset_partial.union_transcript(&other_subset_partial);
912
913 assert_eq!(
914 subset_partial.sent_unsafe(),
915 [0, 0, 0, 0, 4, 5, 6, 7, 8, 9, 0, 0]
916 );
917 assert_eq!(
918 subset_partial.received_unsafe(),
919 [0, 0, 0, 3, 4, 5, 6, 7, 8, 9, 10, 0]
920 );
921 assert_eq!(subset_partial.sent_authed(), &Idx::new(4..10));
922 assert_eq!(subset_partial.received_authed(), &Idx::new(3..11));
923 }
924
925 #[rstest]
926 #[should_panic]
927 fn test_partial_transcript_union_failure(transcript: Transcript) {
928 let mut partial = transcript.to_partial(Idx::new(4..10), Idx::new(3..11));
929
930 let other_transcript = Transcript::new(
931 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
932 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
933 );
934
935 let other_partial = other_transcript.to_partial(Idx::new(6..9), Idx::new(5..6));
936
937 partial.union_transcript(&other_partial);
938 }
939
940 #[rstest]
941 fn test_partial_transcript_union_subseq_success(transcript: Transcript) {
942 let mut partial = transcript.to_partial(Idx::new(4..10), Idx::new(3..11));
943 let sent_seq = Subsequence::new(Idx::new([0..3, 5..7]), [0, 1, 2, 5, 6].into()).unwrap();
944 let recv_seq = Subsequence::new(Idx::new([0..4, 5..7]), [0, 1, 2, 3, 5, 6].into()).unwrap();
945
946 partial.union_subsequence(Direction::Sent, &sent_seq);
947 partial.union_subsequence(Direction::Received, &recv_seq);
948
949 assert_eq!(partial.sent_unsafe(), [0, 1, 2, 0, 4, 5, 6, 7, 8, 9, 0, 0]);
950 assert_eq!(
951 partial.received_unsafe(),
952 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0]
953 );
954 assert_eq!(partial.sent_authed(), &Idx::new([0..3, 4..10]));
955 assert_eq!(partial.received_authed(), &Idx::new(0..11));
956
957 let other_sent_seq = Subsequence::new(Idx::new(0..3), [3, 2, 1].into()).unwrap();
959
960 partial.union_subsequence(Direction::Sent, &other_sent_seq);
961 assert_eq!(partial.sent_unsafe(), [3, 2, 1, 0, 4, 5, 6, 7, 8, 9, 0, 0]);
962 assert_eq!(partial.sent_authed(), &Idx::new([0..3, 4..10]));
963 }
964
965 #[rstest]
966 #[should_panic]
967 fn test_partial_transcript_union_subseq_failure(transcript: Transcript) {
968 let mut partial = transcript.to_partial(Idx::new(4..10), Idx::new(3..11));
969
970 let sent_seq = Subsequence::new(Idx::new([0..3, 13..15]), [0, 1, 2, 5, 6].into()).unwrap();
971
972 partial.union_subsequence(Direction::Sent, &sent_seq);
973 }
974
975 #[rstest]
976 fn test_partial_transcript_set_unauthed_range(transcript: Transcript) {
977 let mut partial = transcript.to_partial(Idx::new(4..10), Idx::new(3..7));
978
979 partial.set_unauthed_range(7, Direction::Sent, 2..5);
980 partial.set_unauthed_range(5, Direction::Sent, 0..2);
981 partial.set_unauthed_range(3, Direction::Received, 4..6);
982 partial.set_unauthed_range(1, Direction::Received, 3..7);
983
984 assert_eq!(partial.sent_unsafe(), [5, 5, 7, 7, 4, 5, 6, 7, 8, 9, 0, 0]);
985 assert_eq!(
986 partial.received_unsafe(),
987 [0, 0, 0, 3, 4, 5, 6, 0, 0, 0, 0, 0]
988 );
989 }
990
991 #[rstest]
992 #[should_panic]
993 fn test_subsequence_new_invalid_len() {
994 let _ = Subsequence::new(Idx::new([0..3, 5..8]), [0, 1, 2, 5, 6].into()).unwrap();
995 }
996
997 #[rstest]
998 #[should_panic]
999 fn test_subsequence_copy_to_invalid_len() {
1000 let seq = Subsequence::new(Idx::new([0..3, 5..7]), [0, 1, 2, 5, 6].into()).unwrap();
1001
1002 let mut data: [u8; 3] = [0, 1, 2];
1003 seq.copy_to(&mut data);
1004 }
1005}