1 /// Helper for calculating the sum of all 16 bit words checksums used in
2 /// in checksum fields in TCP and UDP headers.
3 #[derive(Clone, Debug, Default, Eq, PartialEq)]
4 pub struct Sum16BitWords {
5     /// Partial sum
6     #[cfg(target_pointer_width = "64")]
7     sum: u64,
8 
9     /// Partial sum
10     #[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
11     sum: u32,
12 }
13 
14 impl Sum16BitWords {
new() -> Sum16BitWords15     pub fn new() -> Sum16BitWords {
16         Sum16BitWords { sum: 0 }
17     }
18 
19     /// Add the given slice to the checksum. In case the slice
20     /// has a length that is not multiple of 2 the last byte
21     /// will be padded with 0.
22     #[inline]
23     #[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
add_slice(self, slice: &[u8]) -> Sum16BitWords24     pub fn add_slice(self, slice: &[u8]) -> Sum16BitWords {
25         Sum16BitWords {
26             sum: u32_16bit_word::add_slice(self.sum, slice),
27         }
28     }
29 
30     /// Add the given slice to the checksum. In case the slice
31     /// has a length that is not multiple of 2 the last byte
32     /// will be padded with 0.
33     #[inline]
34     #[cfg(target_pointer_width = "64")]
add_slice(self, slice: &[u8]) -> Sum16BitWords35     pub fn add_slice(self, slice: &[u8]) -> Sum16BitWords {
36         Sum16BitWords {
37             sum: u64_16bit_word::add_slice(self.sum, slice),
38         }
39     }
40 
41     /// Add a 2 byte word.
42     #[inline]
43     #[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
add_2bytes(self, value: [u8; 2]) -> Sum16BitWords44     pub fn add_2bytes(self, value: [u8; 2]) -> Sum16BitWords {
45         Sum16BitWords {
46             sum: u32_16bit_word::add_2bytes(self.sum, value),
47         }
48     }
49 
50     /// Add a 2 byte word.
51     #[inline]
52     #[cfg(target_pointer_width = "64")]
add_2bytes(self, value: [u8; 2]) -> Sum16BitWords53     pub fn add_2bytes(self, value: [u8; 2]) -> Sum16BitWords {
54         Sum16BitWords {
55             sum: u64_16bit_word::add_2bytes(self.sum, value),
56         }
57     }
58 
59     /// Add a 4 byte word.
60     #[inline]
61     #[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
add_4bytes(&mut self, value: [u8; 4]) -> Sum16BitWords62     pub fn add_4bytes(&mut self, value: [u8; 4]) -> Sum16BitWords {
63         Sum16BitWords {
64             sum: u32_16bit_word::add_4bytes(self.sum, value),
65         }
66     }
67 
68     /// Add a 4 byte word.
69     #[inline]
70     #[cfg(target_pointer_width = "64")]
add_4bytes(&mut self, value: [u8; 4]) -> Sum16BitWords71     pub fn add_4bytes(&mut self, value: [u8; 4]) -> Sum16BitWords {
72         Sum16BitWords {
73             sum: u64_16bit_word::add_4bytes(self.sum, value),
74         }
75     }
76 
77     /// Add a 8 byte word.
78     #[inline]
79     #[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
add_8bytes(&mut self, value: [u8; 8]) -> Sum16BitWords80     pub fn add_8bytes(&mut self, value: [u8; 8]) -> Sum16BitWords {
81         self.add_4bytes([value[0], value[1], value[2], value[3]])
82             .add_4bytes([value[4], value[5], value[6], value[7]])
83     }
84 
85     /// Add a 8 byte word.
86     #[inline]
87     #[cfg(target_pointer_width = "64")]
add_8bytes(&mut self, value: [u8; 8]) -> Sum16BitWords88     pub fn add_8bytes(&mut self, value: [u8; 8]) -> Sum16BitWords {
89         Sum16BitWords {
90             sum: u64_16bit_word::add_8bytes(self.sum, value),
91         }
92     }
93 
94     /// Add a 16 bytes.
95     #[inline]
add_16bytes(&mut self, value: [u8; 16]) -> Sum16BitWords96     pub fn add_16bytes(&mut self, value: [u8; 16]) -> Sum16BitWords {
97         self.add_8bytes([
98             value[0], value[1], value[2], value[3], value[4], value[5], value[6], value[7],
99         ])
100         .add_8bytes([
101             value[8], value[9], value[10], value[11], value[12], value[13], value[14], value[15],
102         ])
103     }
104 
105     /// Converts summed up words from an u32 to an u16 ones complement
106     /// which can be used in a ipv4 checksum.
107     #[inline]
108     #[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
ones_complement(&self) -> u16109     pub fn ones_complement(&self) -> u16 {
110         u32_16bit_word::ones_complement(self.sum)
111     }
112 
113     /// Converts summed up words from an u32 to an u16 ones complement
114     /// which can be used in a ipv4 checksum.
115     #[inline]
116     #[cfg(target_pointer_width = "64")]
ones_complement(&self) -> u16117     pub fn ones_complement(&self) -> u16 {
118         u64_16bit_word::ones_complement(self.sum)
119     }
120 
121     /// Converts summed up words from an u32 to an u16 ones complement
122     /// with 0 being replaced by 0xffff (useful for TCP and UDP).
123     ///
124     /// This kind of checksum is used in TCP and UDP headers.
125     #[inline]
126     #[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
to_ones_complement_with_no_zero(&self) -> u16127     pub fn to_ones_complement_with_no_zero(&self) -> u16 {
128         u32_16bit_word::ones_complement_with_no_zero(self.sum)
129     }
130 
131     /// Converts summed up words from an u32 to an u16 ones complement
132     /// with 0 being replaced by 0xffff (useful for TCP and UDP).
133     ///
134     /// This kind of checksum is used in TCP and UDP headers.
135     #[inline]
136     #[cfg(target_pointer_width = "64")]
to_ones_complement_with_no_zero(&self) -> u16137     pub fn to_ones_complement_with_no_zero(&self) -> u16 {
138         u64_16bit_word::ones_complement_with_no_zero(self.sum)
139     }
140 }
141 
142 #[cfg(test)]
143 mod sum16_bit_words_tests {
144     use super::*;
145     use alloc::format;
146 
147     #[test]
new()148     fn new() {
149         assert_eq!(0xffff, Sum16BitWords::new().ones_complement());
150     }
151 
152     #[test]
add_slice()153     fn add_slice() {
154         assert_eq!(
155             !u16::from_ne_bytes([0x12, 0x34]),
156             Sum16BitWords::new()
157                 .add_slice(&[0x12, 0x34])
158                 .ones_complement()
159         );
160     }
161 
162     #[test]
add_2bytes()163     fn add_2bytes() {
164         assert_eq!(
165             !u16::from_ne_bytes([0xf0, 0x0f]),
166             Sum16BitWords::new()
167                 .add_2bytes([0xf0, 0x0f])
168                 .ones_complement()
169         );
170     }
171 
172     #[test]
add_4bytes()173     fn add_4bytes() {
174         assert_eq!(
175             !(u16::from_ne_bytes([0x12, 0x34]) + u16::from_ne_bytes([0x56, 0x78])),
176             Sum16BitWords::new()
177                 .add_4bytes([0x12, 0x34, 0x56, 0x78])
178                 .ones_complement()
179         );
180     }
181 
182     #[test]
add_8bytes()183     fn add_8bytes() {
184         assert_eq!(
185             !(u16::from_ne_bytes([0x12, 0x34])
186                 + u16::from_ne_bytes([0x56, 0x78])
187                 + u16::from_ne_bytes([0x23, 0x22])
188                 + u16::from_ne_bytes([0x34, 0x11])),
189             Sum16BitWords::new()
190                 .add_8bytes([0x12, 0x34, 0x56, 0x78, 0x23, 0x22, 0x34, 0x11])
191                 .ones_complement()
192         );
193     }
194 
195     #[test]
add_16bytes()196     fn add_16bytes() {
197         assert_eq!(
198             u32_16bit_word::ones_complement(u32_16bit_word::add_4bytes(
199                 u32_16bit_word::add_4bytes(
200                     u32_16bit_word::add_4bytes(
201                         u32_16bit_word::add_4bytes(0, [0x12, 0x34, 0x56, 0x78]),
202                         [0x9a, 0xbc, 0xde, 0xf0]
203                     ),
204                     [0x0f, 0xed, 0xcb, 0xa9]
205                 ),
206                 [0x87, 0x65, 0x43, 0x21]
207             )),
208             Sum16BitWords::new()
209                 .add_16bytes([
210                     0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xed, 0xcb, 0xa9, 0x87,
211                     0x65, 0x43, 0x21,
212                 ])
213                 .ones_complement()
214         );
215     }
216 
217     #[test]
ones_complement()218     fn ones_complement() {
219         assert_eq!(
220             !u16::from_ne_bytes([0xf0, 0x0f]),
221             Sum16BitWords::new()
222                 .add_2bytes([0xf0, 0x0f])
223                 .ones_complement()
224         );
225     }
226 
227     #[test]
to_ones_complement_with_no_zero()228     fn to_ones_complement_with_no_zero() {
229         // normal case
230         assert_eq!(
231             !u16::from_ne_bytes([0xf0, 0x0f]),
232             Sum16BitWords::new()
233                 .add_2bytes([0xf0, 0x0f])
234                 .to_ones_complement_with_no_zero()
235         );
236 
237         // zero case
238         assert_eq!(
239             0xffffu16,
240             Sum16BitWords::new()
241                 // ones complement would result in 0
242                 // will be converted to 0xffff as 0
243                 // is a reserved value
244                 .add_2bytes([0xff, 0xff])
245                 .to_ones_complement_with_no_zero()
246         );
247     }
248 
249     #[test]
debug()250     fn debug() {
251         let input = Sum16BitWords::new();
252         assert_eq!(
253             &format!("Sum16BitWords {{ sum: {} }}", input.sum),
254             &format!("{:?}", input)
255         );
256     }
257 
258     #[test]
default()259     fn default() {
260         let d: Sum16BitWords = Default::default();
261         assert_eq!(d.sum, 0);
262     }
263 
264     #[test]
clone_eq()265     fn clone_eq() {
266         let value = Sum16BitWords::new();
267         assert_eq!(value.clone(), value)
268     }
269 }
270 
271 /// Helper functions for calculating a 16 bit checksum using
272 /// a u32 to sum up all values.
273 pub mod u32_16bit_word {
274 
275     /// Add a 4 byte word.
276     #[inline]
add_4bytes(start: u32, value: [u8; 4]) -> u32277     pub fn add_4bytes(start: u32, value: [u8; 4]) -> u32 {
278         let (sum, carry) = start.overflowing_add(u32::from_ne_bytes(value));
279         sum + (carry as u32)
280     }
281 
282     /// Add a 2 byte word.
283     #[inline]
add_2bytes(start: u32, value: [u8; 2]) -> u32284     pub fn add_2bytes(start: u32, value: [u8; 2]) -> u32 {
285         let (sum, carry) = start.overflowing_add(u32::from(u16::from_ne_bytes(value)));
286         sum + (carry as u32)
287     }
288 
289     /// Add the given slice to the checksum. In case the slice
290     /// has a length that is not multiple of 2 the last byte
291     /// will be padded with 0.
292     #[inline]
add_slice(start_sum: u32, slice: &[u8]) -> u32293     pub fn add_slice(start_sum: u32, slice: &[u8]) -> u32 {
294         let mut sum: u32 = start_sum;
295 
296         // sum up all 4 byte values
297         let end_32 = slice.len() - (slice.len() % 4);
298         for i in (0..end_32).step_by(4) {
299             sum = add_4bytes(
300                 sum,
301                 // SAFETY:
302                 // Guranteed to always have at least 4 bytes to read
303                 // from i. As end_32 is gurenateed to be a multiple of
304                 // 4 bytes with a size equal or less then slice.len().
305                 unsafe {
306                     [
307                         *slice.get_unchecked(i),
308                         *slice.get_unchecked(i + 1),
309                         *slice.get_unchecked(i + 2),
310                         *slice.get_unchecked(i + 3),
311                     ]
312                 },
313             );
314         }
315 
316         // in case 2 bytes are left add them as an word
317         if slice.len() - end_32 >= 2 {
318             sum = add_2bytes(
319                 sum,
320                 // SAFETY:
321                 // If check guarantees there to be at least
322                 // 2 bytes.
323                 unsafe {
324                     [
325                         *slice.get_unchecked(end_32),
326                         *slice.get_unchecked(end_32 + 1),
327                     ]
328                 },
329             );
330         }
331 
332         // unaligned end pad the last byte with
333         if 0 != slice.len() % 2 {
334             sum = add_2bytes(
335                 sum,
336                 // SAFETY:
337                 // If check guarantees there to be at least
338                 // 2 bytes.
339                 unsafe { [*slice.get_unchecked(slice.len() - 1), 0] },
340             );
341         }
342 
343         // done
344         sum
345     }
346 
347     /// Converts summed up words from an u32 to an u16 with 0 being replaced by 0xffff (useful
348     /// for TCP and UDP headers).
349     ///
350     /// This kind of checksum is used in TCP and udp headers.
351     #[inline]
ones_complement_with_no_zero(sum: u32) -> u16352     pub fn ones_complement_with_no_zero(sum: u32) -> u16 {
353         // In case of 0 use the ones complement (zero is reserved
354         // value for no checksum).
355         let u16value = ones_complement(sum);
356         if u16value == 0 {
357             0xffff
358         } else {
359             u16value
360         }
361     }
362 
363     /// Converts summed up words from an u32 to an u16 which can be used in a ipv4.
364     #[inline]
ones_complement(sum: u32) -> u16365     pub fn ones_complement(sum: u32) -> u16 {
366         // Add the upper 16 bits to the lower 16 bits twice.
367         //
368         // Notes: Two carry adds are needed as the first one could
369         //        result in an additional carry add.
370         let first = ((sum >> 16) & 0xffff) + (sum & 0xffff);
371         let u16value = (((first >> 16) & 0xffff) + (first & 0xffff)) as u16;
372 
373         // switch back to big endian (allows to use
374         // native endinaess during calculations).
375         !u16value
376     }
377 
378     #[cfg(test)]
379     mod tests {
380         use super::*;
381 
382         #[test]
add_4bytes_test()383         fn add_4bytes_test() {
384             // trivial case
385             assert_eq!(0, add_4bytes(0, [0, 0, 0, 0]));
386             // check that the carry gets added
387             assert_eq!(
388                 0xffff_ffff, // normal overflow would result in 0xffff_fffe
389                 add_4bytes(0xffff_ffff, [0xff, 0xff, 0xff, 0xff])
390             );
391             // non max & min values
392             assert_eq!(
393                 0x1234_5678 + u32::from_ne_bytes([0x23, 0x45, 0x67, 0x89]),
394                 add_4bytes(0x1234_5678, [0x23, 0x45, 0x67, 0x89])
395             );
396         }
397 
398         #[test]
add_2bytes_test()399         fn add_2bytes_test() {
400             // trivial case
401             assert_eq!(0, add_2bytes(0, [0, 0]));
402             // check that the carry gets added
403             assert_eq!(
404                 0x0000_ffff, // normal overflow would result in 0x10000fffe
405                 add_2bytes(0xffff_ffff, [0xff, 0xff])
406             );
407             // non max & min values
408             assert_eq!(
409                 0x1234_5678 + u32::from(u16::from_ne_bytes([0x23, 0x45])),
410                 add_2bytes(0x1234_5678, [0x23, 0x45])
411             );
412         }
413 
414         #[test]
add_slice_test()415         fn add_slice_test() {
416             // empty
417             assert_eq!(0x1234, add_slice(0x1234, &[]));
418 
419             // aligned
420             assert_eq!(
421                 0x1 + u32::from_ne_bytes([0x11, 0x12, 0x13, 0x14])
422                     + u32::from_ne_bytes([0x15, 0x16, 0x17, 0x18])
423                     + u32::from_ne_bytes([0x19, 0x1a, 0x1b, 0x1c])
424                     + u32::from_ne_bytes([0x1d, 0x1e, 0x1f, 0x10]),
425                 add_slice(
426                     0x1,
427                     &[
428                         0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c,
429                         0x1d, 0x1e, 0x1f, 0x10,
430                     ]
431                 )
432             );
433 
434             // aligned with carry
435             assert_eq!(
436                 0x1 +
437                 0x3 + // expected carry
438                 u32::from_ne_bytes([0xf1, 0x11, 0x10, 0xf0]).wrapping_add(
439                     u32::from_ne_bytes([0xf2, 0x12, 0x11, 0xf1]).wrapping_add(
440                         u32::from_ne_bytes([0xf3, 0x13, 0x12, 0xf2]).wrapping_add(
441                             u32::from_ne_bytes([0xf4, 0x14, 0x13, 0xf3])
442                         )
443                     )
444                 ),
445                 add_slice(
446                     0x1,
447                     &[
448                         0xf1, 0x11, 0x10, 0xf0, 0xf2, 0x12, 0x11, 0xf1, 0xf3, 0x13, 0x12, 0xf2,
449                         0xf4, 0x14, 0x13, 0xf3,
450                     ]
451                 )
452             );
453 
454             // 1 byte unalgined
455             assert_eq!(
456                 0x1 + u32::from_ne_bytes([0x11, 0x12, 0x13, 0x14])
457                     + u32::from_ne_bytes([0x15, 0x16, 0x17, 0x18])
458                     + u32::from_ne_bytes([0x19, 0x1a, 0x1b, 0x1c])
459                     + u32::from(u16::from_ne_bytes([0x1d, 0x1e]))
460                     + u32::from(u16::from_ne_bytes([0x1f, 0x00])),
461                 add_slice(
462                     0x1,
463                     &[
464                         0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c,
465                         0x1d, 0x1e, 0x1f,
466                     ]
467                 )
468             );
469 
470             // 2 byte unaligned
471             assert_eq!(
472                 0x1 + u32::from_ne_bytes([0x11, 0x12, 0x13, 0x14])
473                     + u32::from_ne_bytes([0x15, 0x16, 0x17, 0x18])
474                     + u32::from_ne_bytes([0x19, 0x1a, 0x1b, 0x1c])
475                     + u32::from(u16::from_ne_bytes([0x1d, 0x1e])),
476                 add_slice(
477                     0x1,
478                     &[
479                         0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c,
480                         0x1d, 0x1e,
481                     ]
482                 )
483             );
484 
485             // 4 byte unaligned
486             assert_eq!(
487                 0x1 + u32::from_ne_bytes([0x11, 0x12, 0x13, 0x14])
488                     + u32::from_ne_bytes([0x15, 0x16, 0x17, 0x18])
489                     + u32::from_ne_bytes([0x19, 0x1a, 0x1b, 0x1c])
490                     + u32::from(u16::from_ne_bytes([0x1d, 0x00])),
491                 add_slice(
492                     0x1,
493                     &[
494                         0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c,
495                         0x1d,
496                     ]
497                 )
498             );
499         }
500 
501         #[test]
ones_complement_with_no_zero_test()502         fn ones_complement_with_no_zero_test() {
503             // zero case
504             assert_eq!(0xffff, ones_complement_with_no_zero(0));
505 
506             // 0xffff should stay 0xffff (0 is reserved for no checksum)
507             assert_eq!(0xffff, ones_complement_with_no_zero(0xffff));
508 
509             // big endian conversion check
510             assert_eq!(!0x1234u16, ones_complement_with_no_zero(0x1234),);
511 
512             // add of the upper and lower 16 bits without a carry
513             assert_eq!(
514                 !(0x2345u16 + 0x1234),
515                 ones_complement_with_no_zero(0x2345_1234),
516             );
517 
518             // add which in itself will again produce a carry
519             assert_eq!(
520                 !(((0x1456u32 + 0xf123u32 + 1u32) & 0xffff) as u16),
521                 ones_complement_with_no_zero(0x1456_f123),
522             );
523         }
524 
525         #[test]
ones_complement_test()526         fn ones_complement_test() {
527             // zero case
528             assert_eq!(0xffff, ones_complement(0));
529 
530             // check that zero is not reserved
531             assert_eq!(0, ones_complement(0xffff));
532 
533             // big endian conversion check
534             assert_eq!(!0x1234u16, ones_complement(0x1234),);
535 
536             // add of the upper and lower 16 bits without a carry
537             assert_eq!(!(0x2345u16 + 0x1234u16), ones_complement(0x2345_1234),);
538 
539             // add which in itself will again produce a carry
540             assert_eq!(
541                 !(((0x1456u32 + 0xf123u32 + 1u32) & 0xffff) as u16),
542                 ones_complement(0x1456_f123),
543             );
544         }
545     }
546 }
547 
548 /// Helper functions for calculating a 16 bit checksum using
549 /// a u64 to sum up all values.
550 pub mod u64_16bit_word {
551 
552     /// Add a 8 byte word.
553     #[inline]
add_8bytes(start: u64, value: [u8; 8]) -> u64554     pub fn add_8bytes(start: u64, value: [u8; 8]) -> u64 {
555         let (sum, carry) = start.overflowing_add(u64::from_ne_bytes(value));
556         sum + (carry as u64)
557     }
558 
559     /// Add a 4 byte word.
560     #[inline]
add_4bytes(start: u64, value: [u8; 4]) -> u64561     pub fn add_4bytes(start: u64, value: [u8; 4]) -> u64 {
562         let (sum, carry) = start.overflowing_add(u64::from(u32::from_ne_bytes(value)));
563         sum + (carry as u64)
564     }
565 
566     /// Add a 2 byte word.
567     #[inline]
add_2bytes(start: u64, value: [u8; 2]) -> u64568     pub fn add_2bytes(start: u64, value: [u8; 2]) -> u64 {
569         let (sum, carry) = start.overflowing_add(u64::from(u16::from_ne_bytes(value)));
570         sum + (carry as u64)
571     }
572 
573     /// Add the given slice to the checksum. In case the slice
574     /// has a length that is not multiple of 2 the last byte
575     /// will be padded with 0.
576     #[inline]
add_slice(start_sum: u64, slice: &[u8]) -> u64577     pub fn add_slice(start_sum: u64, slice: &[u8]) -> u64 {
578         let mut sum: u64 = start_sum;
579 
580         // sum up all 4 byte values
581         let end_64 = slice.len() - (slice.len() % 8);
582         for i in (0..end_64).step_by(8) {
583             sum = add_8bytes(
584                 sum,
585                 // SAFETY:
586                 // Guranteed to always have at least 8 bytes to read
587                 // from i. As end_64 is gurenateed to be a multiple of
588                 // 8 bytes with a size equal or less then slice.len().
589                 unsafe {
590                     [
591                         *slice.get_unchecked(i),
592                         *slice.get_unchecked(i + 1),
593                         *slice.get_unchecked(i + 2),
594                         *slice.get_unchecked(i + 3),
595                         *slice.get_unchecked(i + 4),
596                         *slice.get_unchecked(i + 5),
597                         *slice.get_unchecked(i + 6),
598                         *slice.get_unchecked(i + 7),
599                     ]
600                 },
601             );
602         }
603 
604         // in case 4 or more bytes are left add the first 4 bytes
605         let end_32 = if slice.len() - end_64 >= 4 {
606             sum = add_4bytes(
607                 sum,
608                 // SAFETY:
609                 // If check guarantees there to be at least
610                 // 2 bytes.
611                 unsafe {
612                     [
613                         *slice.get_unchecked(end_64),
614                         *slice.get_unchecked(end_64 + 1),
615                         *slice.get_unchecked(end_64 + 2),
616                         *slice.get_unchecked(end_64 + 3),
617                     ]
618                 },
619             );
620 
621             // shift by 4
622             end_64 + 4
623         } else {
624             end_64
625         };
626 
627         // in case 2 bytes are left add them as an word
628         if slice.len() - end_32 >= 2 {
629             sum = add_2bytes(
630                 sum,
631                 // SAFETY:
632                 // If check guarantees there to be at least
633                 // 2 bytes.
634                 unsafe {
635                     [
636                         *slice.get_unchecked(end_32),
637                         *slice.get_unchecked(end_32 + 1),
638                     ]
639                 },
640             );
641         }
642 
643         // unaligned end pad the last byte with
644         if 0 != slice.len() % 2 {
645             sum = add_2bytes(
646                 sum,
647                 // SAFETY:
648                 // If check guarantees there to be at least
649                 // 2 bytes.
650                 unsafe { [*slice.get_unchecked(slice.len() - 1), 0] },
651             );
652         }
653 
654         // done
655         sum
656     }
657 
658     /// Converts summed up words from an u64 to an u16 with 0 being replaced by 0xffff (useful
659     /// for TCP and UDP headers).
660     ///
661     /// This kind of checksum is used in TCP and udp headers.
662     #[inline]
ones_complement_with_no_zero(sum: u64) -> u16663     pub fn ones_complement_with_no_zero(sum: u64) -> u16 {
664         // In case of 0 use the ones complement (zero is reserved
665         // value for no checksum).
666         let u16value = ones_complement(sum);
667         if u16value == 0 {
668             0xffff
669         } else {
670             u16value
671         }
672     }
673 
674     /// Converts summed up words from an u64 to an u16 which can be used in a ipv4.
675     #[inline]
ones_complement(sum: u64) -> u16676     pub fn ones_complement(sum: u64) -> u16 {
677         let first = ((sum >> 48) & 0xffff)
678             + ((sum >> 32) & 0xffff)
679             + ((sum >> 16) & 0xffff)
680             + (sum & 0xffff);
681         // Add the upper 16 bits to the lower 16 bits twice.
682         //
683         // Notes: Two carry adds are needed as the first one could
684         //        result in an additional carry add.
685         let second = ((first >> 16) & 0xffff) + (first & 0xffff);
686         let u16value = (((second >> 16) & 0xffff) + (second & 0xffff)) as u16;
687 
688         // switch back to big endian (allows to use
689         // native endinaess during calculations).
690         !u16value
691     }
692 
693     #[cfg(test)]
694     mod tests {
695         use super::*;
696         use proptest::prelude::*;
697 
698         #[test]
add_8bytes_test()699         fn add_8bytes_test() {
700             // trivial case
701             assert_eq!(0, add_8bytes(0, [0, 0, 0, 0, 0, 0, 0, 0]));
702             // check that the carry gets added
703             assert_eq!(
704                 0xffff_ffff_ffff_ffff, // normal overflow would result in 0xffff_ffff_ffff_fffe
705                 add_8bytes(
706                     0xffff_ffff_ffff_ffff,
707                     [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
708                 )
709             );
710             // non max & min values
711             assert_eq!(
712                 0x1234_5678_1234_5678
713                     + u64::from_ne_bytes([0x23, 0x45, 0x67, 0x89, 0x11, 0x22, 0x33, 0x44]),
714                 add_8bytes(
715                     0x1234_5678_1234_5678,
716                     [0x23, 0x45, 0x67, 0x89, 0x11, 0x22, 0x33, 0x44]
717                 )
718             );
719         }
720 
721         #[test]
add_4bytes_test()722         fn add_4bytes_test() {
723             // trivial case
724             assert_eq!(0, add_4bytes(0, [0, 0, 0, 0]));
725             // check that the carry gets added
726             assert_eq!(
727                 0xffff_ffff, // normal overflow would result in 0xffff_fffe
728                 add_4bytes(0xffff_ffff_ffff_ffff, [0xff, 0xff, 0xff, 0xff])
729             );
730             // non max & min values
731             assert_eq!(
732                 0x1234_5678_1234_5678 + u64::from(u32::from_ne_bytes([0x23, 0x45, 0x67, 0x89])),
733                 add_4bytes(0x1234_5678_1234_5678, [0x23, 0x45, 0x67, 0x89])
734             );
735         }
736 
737         #[test]
add_2bytes_test()738         fn add_2bytes_test() {
739             // trivial case
740             assert_eq!(0, add_2bytes(0, [0, 0]));
741             // check that the carry gets added
742             assert_eq!(
743                 0xffff, // normal overflow would result in 0xfffe
744                 add_2bytes(0xffff_ffff_ffff_ffff, [0xff, 0xff])
745             );
746             // non max & min values
747             assert_eq!(
748                 0x9876_0123_1234_5678 + u64::from(u16::from_ne_bytes([0x23, 0x45])),
749                 add_2bytes(0x9876_0123_1234_5678, [0x23, 0x45])
750             );
751         }
752 
753         #[test]
add_slice_test()754         fn add_slice_test() {
755             // empty
756             assert_eq!(0x1234, add_slice(0x1234, &[]));
757 
758             // aligned
759             assert_eq!(
760                 0x1 + u64::from_ne_bytes([0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18])
761                     + u64::from_ne_bytes([0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10]),
762                 add_slice(
763                     0x1,
764                     &[
765                         0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c,
766                         0x1d, 0x1e, 0x1f, 0x10,
767                     ]
768                 )
769             );
770 
771             // aligned with carry
772             assert_eq!(
773                 0x1 +
774                 0x1 + // expected carry
775                 u64::from_ne_bytes([0xf1, 0x11, 0x10, 0xf0, 0xf2, 0x12, 0x11, 0xf1]).wrapping_add(
776                     u64::from_ne_bytes([0xf3, 0x13, 0x12, 0xf2, 0xf4, 0x14, 0x13, 0xf3])
777                 ),
778                 add_slice(
779                     0x1,
780                     &[
781                         0xf1, 0x11, 0x10, 0xf0, 0xf2, 0x12, 0x11, 0xf1, 0xf3, 0x13, 0x12, 0xf2,
782                         0xf4, 0x14, 0x13, 0xf3,
783                     ]
784                 )
785             );
786 
787             // unaligned access
788             {
789                 let base_data = [
790                     0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
791                     0x1e, 0x1f, 0x00,
792                 ];
793 
794                 // 1 byte unaligned
795                 assert_eq!(
796                     0x1 + u64::from_ne_bytes([0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18])
797                         + u64::from(u32::from_ne_bytes([0x19, 0x1a, 0x1b, 0x1c]))
798                         + u64::from(u16::from_ne_bytes([0x1d, 0x1e]))
799                         + u64::from(u16::from_ne_bytes([0x1f, 0x00])),
800                     add_slice(0x1, &base_data[..base_data.len() - 1])
801                 );
802 
803                 // 2 byte unaligned
804                 assert_eq!(
805                     0x1 + u64::from_ne_bytes([0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18])
806                         + u64::from(u32::from_ne_bytes([0x19, 0x1a, 0x1b, 0x1c]))
807                         + u64::from(u16::from_ne_bytes([0x1d, 0x1e])),
808                     add_slice(0x1, &base_data[..base_data.len() - 2])
809                 );
810 
811                 // 3 byte unaligned
812                 assert_eq!(
813                     0x1 + u64::from_ne_bytes([0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18])
814                         + u64::from(u32::from_ne_bytes([0x19, 0x1a, 0x1b, 0x1c]))
815                         + u64::from(u16::from_ne_bytes([0x1d, 0x00])),
816                     add_slice(0x1, &base_data[..base_data.len() - 3])
817                 );
818 
819                 // 4 byte unaligned
820                 assert_eq!(
821                     0x1 + u64::from_ne_bytes([0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18])
822                         + u64::from(u32::from_ne_bytes([0x19, 0x1a, 0x1b, 0x1c])),
823                     add_slice(0x1, &base_data[..base_data.len() - 4])
824                 );
825 
826                 // 5 byte unaligned
827                 assert_eq!(
828                     0x1 + u64::from_ne_bytes([0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18])
829                         + u64::from(u16::from_ne_bytes([0x19, 0x1a]))
830                         + u64::from(u16::from_ne_bytes([0x1b, 0x00])),
831                     add_slice(0x1, &base_data[..base_data.len() - 5])
832                 );
833 
834                 // 6 byte unaligned
835                 assert_eq!(
836                     0x1 + u64::from_ne_bytes([0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18])
837                         + u64::from(u16::from_ne_bytes([0x19, 0x1a])),
838                     add_slice(0x1, &base_data[..base_data.len() - 6])
839                 );
840 
841                 // 6 byte unaligned
842                 assert_eq!(
843                     0x1 + u64::from_ne_bytes([0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18])
844                         + u64::from(u16::from_ne_bytes([0x19, 0x00])),
845                     add_slice(0x1, &base_data[..base_data.len() - 7])
846                 );
847             }
848         }
849 
850         #[test]
ones_complement_with_no_zero_test()851         fn ones_complement_with_no_zero_test() {
852             // zero case
853             assert_eq!(0xffff, ones_complement_with_no_zero(0));
854 
855             // 0xffff should stay 0xffff (0 is reserved for no checksum)
856             assert_eq!(0xffff, ones_complement_with_no_zero(0xffff));
857 
858             // big endian conversion check
859             assert_eq!(!0x1234u16, ones_complement_with_no_zero(0x1234),);
860 
861             // add of the upper and lower 16 bits without a carry
862             assert_eq!(
863                 !(0x2456u16 + 0x1345 + 0x2345u16 + 0x1234u16),
864                 ones_complement_with_no_zero(0x2456_1345_2345_1234),
865             );
866 
867             // add which in itself will again produce two as carry
868             assert_eq!(
869                 !(((0x1234 + 0xf234u32 + 0x1456u32 + 0xf123u32 + 2u32) & 0xffff) as u16),
870                 ones_complement_with_no_zero(0x1234_f234_1456_f123),
871             );
872         }
873 
874         #[test]
ones_complement_test()875         fn ones_complement_test() {
876             // zero case
877             assert_eq!(0xffff, ones_complement(0));
878 
879             // check that zero is not reserved
880             assert_eq!(0, ones_complement(0xffff));
881 
882             // big endian conversion check
883             assert_eq!(!0x1234u16, ones_complement(0x1234),);
884 
885             // add of the upper and lower 16 bits without a carry
886             assert_eq!(
887                 !(0x2456u16 + 0x1345 + 0x2345u16 + 0x1234u16),
888                 ones_complement(0x2456_1345_2345_1234),
889             );
890 
891             // add which in itself will again produce two as carry
892             assert_eq!(
893                 !(((0x1234 + 0xf234u32 + 0x1456u32 + 0xf123u32 + 2u32) & 0xffff) as u16),
894                 ones_complement(0x1234_f234_1456_f123),
895             );
896 
897             // will result in a first 16bit sum that will have to be
898             // carry added twice
899             assert_eq!(!1, ones_complement(0x02f6_e312_7fd7_9a20),);
900         }
901 
902         proptest! {
903             #[test]
904             #[cfg_attr(miri, ignore)] // vec allocation reduces miri runspeed too much
905             fn u32_u16_comparison(
906                 data in proptest::collection::vec(any::<u8>(), 0..0xfffusize)
907             ) {
908                 use crate::checksum::*;
909 
910                 let u32_oc = u32_16bit_word::ones_complement(
911                     u32_16bit_word::add_slice(0, &data)
912                 );
913                 let u64_oc = u64_16bit_word::ones_complement(
914                     u64_16bit_word::add_slice(0, &data)
915                 );
916                 assert_eq!(u32_oc, u64_oc);
917 
918                 let struct_oc = Sum16BitWords::new()
919                     .add_slice(&data)
920                     .ones_complement();
921                 assert_eq!(u32_oc, struct_oc);
922             }
923         }
924     }
925 }
926