tlsn_core/transcript/encoding/
encoder.rs1use std::ops::Range;
2
3use crate::transcript::Direction;
4use itybity::ToBits;
5use rand::{RngCore, SeedableRng};
6use rand_chacha::ChaCha12Rng;
7use serde::{Deserialize, Serialize};
8
9const BIT_ENCODING_SIZE: usize = 16;
11const BYTE_ENCODING_SIZE: usize = 128;
13
14#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
16pub struct EncoderSecret {
17 seed: [u8; 32],
18 delta: [u8; BIT_ENCODING_SIZE],
19}
20
21opaque_debug::implement!(EncoderSecret);
22
23impl EncoderSecret {
24 pub fn new(seed: [u8; 32], delta: [u8; 16]) -> Self {
31 Self { seed, delta }
32 }
33
34 pub fn seed(&self) -> &[u8; 32] {
36 &self.seed
37 }
38
39 pub fn delta(&self) -> &[u8; 16] {
41 &self.delta
42 }
43}
44
45pub fn new_encoder(secret: &EncoderSecret) -> impl Encoder {
47 ChaChaEncoder::new(secret)
48}
49
50pub(crate) struct ChaChaEncoder {
51 seed: [u8; 32],
52 delta: [u8; 16],
53}
54
55impl ChaChaEncoder {
56 pub(crate) fn new(secret: &EncoderSecret) -> Self {
57 let seed = *secret.seed();
58 let delta = *secret.delta();
59
60 Self { seed, delta }
61 }
62
63 pub(crate) fn new_prg(&self, stream_id: u64) -> ChaCha12Rng {
64 let mut prg = ChaCha12Rng::from_seed(self.seed);
65 prg.set_stream(stream_id);
66 prg.set_word_pos(0);
67 prg
68 }
69}
70
71pub trait Encoder {
76 fn encode_range(&self, direction: Direction, range: Range<usize>, dest: &mut Vec<u8>);
79
80 fn encode_data(
82 &self,
83 direction: Direction,
84 range: Range<usize>,
85 data: &[u8],
86 dest: &mut Vec<u8>,
87 );
88}
89
90impl Encoder for ChaChaEncoder {
91 fn encode_range(&self, direction: Direction, range: Range<usize>, dest: &mut Vec<u8>) {
92 const WORDS_PER_BYTE: u128 = 8 * 128 / 32;
94
95 let stream_id: u64 = match direction {
96 Direction::Sent => 0,
97 Direction::Received => 1,
98 };
99
100 let mut prg = self.new_prg(stream_id);
101 let len = range.len() * BYTE_ENCODING_SIZE;
102 let pos = dest.len();
103
104 dest.resize(pos + len, 0);
106
107 prg.set_word_pos(range.start as u128 * WORDS_PER_BYTE);
109 prg.fill_bytes(&mut dest[pos..pos + len]);
110 }
111
112 fn encode_data(
113 &self,
114 direction: Direction,
115 range: Range<usize>,
116 data: &[u8],
117 dest: &mut Vec<u8>,
118 ) {
119 const ZERO: [u8; 16] = [0; BIT_ENCODING_SIZE];
120
121 let pos = dest.len();
122
123 self.encode_range(direction, range, dest);
125 let dest = &mut dest[pos..];
126
127 for (pos, bit) in data.iter_lsb0().enumerate() {
128 let summand = if bit { &self.delta } else { &ZERO };
131 dest[pos * BIT_ENCODING_SIZE..(pos + 1) * BIT_ENCODING_SIZE]
132 .iter_mut()
133 .zip(summand)
134 .for_each(|(a, b)| *a ^= *b);
135 }
136 }
137}