Skip to main content

raptorq/
base.rs

1#[cfg(feature = "std")]
2use std::{cmp::min, vec::Vec};
3
4#[cfg(not(feature = "std"))]
5use core::cmp::min;
6
7#[cfg(not(feature = "std"))]
8use alloc::vec::Vec;
9
10use crate::rng::rand;
11use crate::systematic_constants::{
12    MAX_SOURCE_SYMBOLS_PER_BLOCK, SYSTEMATIC_INDICES_AND_PARAMETERS,
13};
14use crate::util::int_div_ceil;
15#[cfg(feature = "serde_support")]
16use serde::{Deserialize, Serialize};
17
18// As defined in section 3.2
19#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
20#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))]
21pub struct PayloadId {
22    source_block_number: u8,
23    encoding_symbol_id: u32,
24}
25
26impl PayloadId {
27    pub fn new(source_block_number: u8, encoding_symbol_id: u32) -> PayloadId {
28        // Encoding Symbol ID must be a 24-bit unsigned int
29        assert!(encoding_symbol_id < 16777216);
30        PayloadId {
31            source_block_number,
32            encoding_symbol_id,
33        }
34    }
35
36    #[allow(clippy::trivially_copy_pass_by_ref)]
37    pub fn deserialize(data: &[u8; 4]) -> PayloadId {
38        PayloadId {
39            source_block_number: data[0],
40            encoding_symbol_id: ((data[1] as u32) << 16) + ((data[2] as u32) << 8) + data[3] as u32,
41        }
42    }
43
44    pub fn serialize(&self) -> [u8; 4] {
45        [
46            self.source_block_number,
47            (self.encoding_symbol_id >> 16) as u8,
48            ((self.encoding_symbol_id >> 8) & 0xFF) as u8,
49            (self.encoding_symbol_id & 0xFF) as u8,
50        ]
51    }
52
53    pub fn source_block_number(&self) -> u8 {
54        self.source_block_number
55    }
56
57    pub fn encoding_symbol_id(&self) -> u32 {
58        self.encoding_symbol_id
59    }
60}
61
62/// Contains encoding symbols generated from a source block.
63///
64/// As defined in section [4.4.2](https://tools.ietf.org/html/rfc6330#section-4.4.2).
65#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
66#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))]
67pub struct EncodingPacket {
68    pub(crate) payload_id: PayloadId,
69    pub(crate) data: Vec<u8>,
70}
71
72impl EncodingPacket {
73    pub fn new(payload_id: PayloadId, data: Vec<u8>) -> EncodingPacket {
74        EncodingPacket { payload_id, data }
75    }
76
77    pub fn deserialize(data: &[u8]) -> EncodingPacket {
78        let payload_data = [data[0], data[1], data[2], data[3]];
79        EncodingPacket {
80            payload_id: PayloadId::deserialize(&payload_data),
81            data: Vec::from(&data[4..]),
82        }
83    }
84
85    pub fn serialize(&self) -> Vec<u8> {
86        let mut serialized = Vec::with_capacity(4 + self.data.len());
87        serialized.extend_from_slice(&self.payload_id.serialize());
88        serialized.extend(self.data.iter());
89        return serialized;
90    }
91
92    /// Retrieves packet payload ID.
93    pub fn payload_id(&self) -> &PayloadId {
94        &self.payload_id
95    }
96
97    /// Retrieves packet payload.
98    pub fn data(&self) -> &[u8] {
99        &self.data
100    }
101
102    /// Split a packet into its underlying ID and payload.
103    pub fn split(self) -> (PayloadId, Vec<u8>) {
104        (self.payload_id, self.data)
105    }
106}
107
108// As defined in section 3.3.2 and 3.3.3
109#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
110#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))]
111pub struct ObjectTransmissionInformation {
112    transfer_length: u64, // Limited to u40
113    symbol_size: u16,
114    num_source_blocks: u8,
115    num_sub_blocks: u16,
116    symbol_alignment: u8,
117}
118
119impl ObjectTransmissionInformation {
120    pub fn new(
121        transfer_length: u64,
122        symbol_size: u16,
123        source_blocks: u8,
124        sub_blocks: u16,
125        alignment: u8,
126    ) -> ObjectTransmissionInformation {
127        // See errata (https://www.rfc-editor.org/errata/eid5548)
128        assert!(transfer_length <= 942574504275);
129        assert_eq!(symbol_size % alignment as u16, 0);
130        // See section 4.4.1.2. "These parameters MUST be set so that ceil(ceil(F/T)/Z) <= K'_max."
131
132        if (symbol_size != 0) && (source_blocks != 0) {
133            let symbols_required = int_div_ceil(
134                int_div_ceil(transfer_length, symbol_size as u64) as u64,
135                source_blocks as u64,
136            );
137            assert!((symbols_required) <= MAX_SOURCE_SYMBOLS_PER_BLOCK);
138        }
139
140        ObjectTransmissionInformation {
141            transfer_length,
142            symbol_size,
143            num_source_blocks: source_blocks,
144            num_sub_blocks: sub_blocks,
145            symbol_alignment: alignment,
146        }
147    }
148
149    pub fn deserialize(data: &[u8; 12]) -> ObjectTransmissionInformation {
150        ObjectTransmissionInformation {
151            transfer_length: ((data[0] as u64) << 32)
152                + ((data[1] as u64) << 24)
153                + ((data[2] as u64) << 16)
154                + ((data[3] as u64) << 8)
155                + (data[4] as u64),
156            symbol_size: ((data[6] as u16) << 8) + data[7] as u16,
157            num_source_blocks: data[8],
158            num_sub_blocks: ((data[9] as u16) << 8) + data[10] as u16,
159            symbol_alignment: data[11],
160        }
161    }
162
163    pub fn serialize(&self) -> [u8; 12] {
164        [
165            ((self.transfer_length >> 32) & 0xFF) as u8,
166            ((self.transfer_length >> 24) & 0xFF) as u8,
167            ((self.transfer_length >> 16) & 0xFF) as u8,
168            ((self.transfer_length >> 8) & 0xFF) as u8,
169            (self.transfer_length & 0xFF) as u8,
170            0, // Reserved
171            (self.symbol_size >> 8) as u8,
172            (self.symbol_size & 0xFF) as u8,
173            self.num_source_blocks,
174            (self.num_sub_blocks >> 8) as u8,
175            (self.num_sub_blocks & 0xFF) as u8,
176            self.symbol_alignment,
177        ]
178    }
179
180    pub fn transfer_length(&self) -> u64 {
181        self.transfer_length
182    }
183
184    pub fn symbol_size(&self) -> u16 {
185        self.symbol_size
186    }
187
188    pub fn source_blocks(&self) -> u8 {
189        self.num_source_blocks
190    }
191
192    pub fn sub_blocks(&self) -> u16 {
193        self.num_sub_blocks
194    }
195
196    pub fn symbol_alignment(&self) -> u8 {
197        self.symbol_alignment
198    }
199
200    pub(crate) fn generate_encoding_parameters(
201        transfer_length: u64,
202        max_packet_size: u16,
203        decoder_memory_requirement: u64,
204    ) -> ObjectTransmissionInformation {
205        let (alignment, sub_symbol_size) = if max_packet_size >= 8 * 8 {
206            (8, 8)
207        } else {
208            (1, 1)
209        };
210        assert!(max_packet_size >= alignment);
211        let symbol_size = max_packet_size - (max_packet_size % alignment);
212
213        let kt = int_div_ceil(transfer_length, symbol_size as u64);
214
215        let n_max = symbol_size as u32 / (sub_symbol_size * alignment) as u32;
216
217        let kl = |n: u32| -> u32 {
218            for &(kprime, _, _, _, _) in SYSTEMATIC_INDICES_AND_PARAMETERS.iter().rev() {
219                let x = int_div_ceil(symbol_size as u64, alignment as u64 * n as u64);
220                if kprime <= (decoder_memory_requirement / (alignment as u64 * x as u64)) as u32 {
221                    return kprime;
222                }
223            }
224            unreachable!();
225        };
226
227        let num_source_blocks = int_div_ceil(kt as u64, kl(n_max) as u64);
228
229        let mut n = 1;
230        for i in 1..=n_max {
231            n = i;
232            if int_div_ceil(kt as u64, num_source_blocks as u64) <= kl(n) {
233                break;
234            }
235        }
236
237        ObjectTransmissionInformation {
238            transfer_length,
239            symbol_size,
240            num_source_blocks: num_source_blocks as u8,
241            num_sub_blocks: n as u16,
242            symbol_alignment: alignment as u8,
243        }
244    }
245
246    pub fn with_defaults(
247        transfer_length: u64,
248        max_packet_size: u16,
249    ) -> ObjectTransmissionInformation {
250        ObjectTransmissionInformation::generate_encoding_parameters(
251            transfer_length,
252            max_packet_size,
253            10 * 1024 * 1024,
254        )
255    }
256}
257
258// Partition[I, J] function, as defined in section 4.4.1.2
259pub fn partition<TI, TJ>(i: TI, j: TJ) -> (u32, u32, u32, u32)
260where
261    TI: Into<u32>,
262    TJ: Into<u32>,
263{
264    let (i, j) = (i.into(), j.into());
265    let il = int_div_ceil(i as u64, j as u64);
266
267    let is = i / j;
268
269    let jl = i - is * j;
270    let js = j - jl;
271    (il, is, jl, js)
272}
273
274// Deg[v] as defined in section 5.3.5.2
275pub fn deg(v: u32, lt_symbols: u32) -> u32 {
276    assert!(v < 1048576);
277    let f: [u32; 31] = [
278        0, 5243, 529531, 704294, 791675, 844104, 879057, 904023, 922747, 937311, 948962, 958494,
279        966438, 973160, 978921, 983914, 988283, 992138, 995565, 998631, 1001391, 1003887, 1006157,
280        1008229, 1010129, 1011876, 1013490, 1014983, 1016370, 1017662, 1048576,
281    ];
282
283    #[allow(clippy::needless_range_loop)]
284    for d in 1..f.len() {
285        if v < f[d] {
286            return min(d as u32, lt_symbols - 2);
287        }
288    }
289    unreachable!();
290}
291
292// Tuple[K', X] as defined in section 5.3.5.4
293#[allow(non_snake_case, clippy::many_single_char_names)]
294pub fn intermediate_tuple(
295    internal_symbol_id: u32,
296    lt_symbols: u32,
297    systematic_index: u32,
298    p1: u32,
299) -> (u32, u32, u32, u32, u32, u32) {
300    let J = systematic_index;
301    let W = lt_symbols;
302    let P1 = p1;
303
304    let mut A = 53591 + J * 997;
305
306    if A.is_multiple_of(2) {
307        A += 1;
308    }
309
310    let B = 10267 * (J + 1);
311    let y: u32 = ((B as u64 + internal_symbol_id as u64 * A as u64) % 4294967296) as u32;
312    let v = rand(y, 0u32, 1048576);
313    let d = deg(v, W);
314    let a = 1 + rand(y, 1u32, W - 1);
315    let b = rand(y, 2u32, W);
316
317    let d1 = if d < 4 {
318        2 + rand(internal_symbol_id, 3u32, 2)
319    } else {
320        2
321    };
322
323    let a1 = 1 + rand(internal_symbol_id, 4u32, P1 - 1);
324    let b1 = rand(internal_symbol_id, 5u32, P1);
325
326    (d, a, b, d1, a1, b1)
327}
328
329#[cfg(test)]
330mod tests {
331    use crate::{EncodingPacket, ObjectTransmissionInformation, PayloadId};
332    use rand::Rng;
333
334    #[test]
335    fn max_transfer_size() {
336        ObjectTransmissionInformation::new(942574504275, 65535, 255, 1, 1);
337    }
338
339    #[test]
340    fn payload_id_serialization() {
341        let payload_id = PayloadId::new(
342            rand::rng().random(),
343            rand::rng().random_range(0..(256 * 256 * 256)),
344        );
345        let deserialized = PayloadId::deserialize(&payload_id.serialize());
346        assert_eq!(deserialized, payload_id);
347    }
348
349    #[test]
350    fn encoding_packet_serialization() {
351        let payload_id = PayloadId::new(
352            rand::rng().random(),
353            rand::rng().random_range(0..(256 * 256 * 256)),
354        );
355        let packet = EncodingPacket::new(payload_id, vec![rand::rng().random()]);
356        let deserialized = EncodingPacket::deserialize(&packet.serialize());
357        assert_eq!(deserialized, packet);
358    }
359
360    #[test]
361    fn oti_serialization() {
362        let oti = ObjectTransmissionInformation::with_defaults(
363            rand::rng().random_range(0..(256 * 256 * 256 * 256 * 256)),
364            rand::rng().random(),
365        );
366        let deserialized = ObjectTransmissionInformation::deserialize(&oti.serialize());
367        assert_eq!(deserialized, oti);
368    }
369}