1use crate::{endian::*, polyfill};
16
17#[repr(C)]
22#[derive(Copy, Clone)]
23pub struct Block {
24 subblocks: [u64; 2],
25}
26
27pub const BLOCK_LEN: usize = 16;
28
29impl Block {
30 #[inline]
31 pub fn zero() -> Self {
32 Self { subblocks: [0, 0] }
33 }
34
35 #[inline]
37 pub fn from_u64_le(first: LittleEndian<u64>, second: LittleEndian<u64>) -> Self {
38 #[allow(deprecated)]
39 Self {
40 subblocks: [first.into_raw_value(), second.into_raw_value()],
41 }
42 }
43
44 #[inline]
46 pub fn from_u64_be(first: BigEndian<u64>, second: BigEndian<u64>) -> Self {
47 #[allow(deprecated)]
48 Self {
49 subblocks: [first.into_raw_value(), second.into_raw_value()],
50 }
51 }
52
53 pub fn u64s_be_to_native(&self) -> [u64; 2] {
54 [
55 u64::from_be(self.subblocks[0]),
56 u64::from_be(self.subblocks[1]),
57 ]
58 }
59
60 #[inline]
61 pub fn overwrite_part_at(&mut self, index: usize, a: &[u8]) {
62 let mut tmp: [u8; BLOCK_LEN] = *self.as_ref();
63 tmp[index..][..a.len()].copy_from_slice(a);
64 *self = Self::from(&tmp)
65 }
66
67 #[inline]
68 pub fn zero_from(&mut self, index: usize) {
69 let mut tmp: [u8; BLOCK_LEN] = *self.as_ref();
70 polyfill::slice::fill(&mut tmp[index..], 0);
71 *self = Self::from(&tmp)
72 }
73
74 #[inline]
75 pub fn bitxor_assign(&mut self, a: Block) {
76 for (r, a) in self.subblocks.iter_mut().zip(a.subblocks.iter()) {
77 *r ^= *a;
78 }
79 }
80}
81
82impl From<&'_ [u8; BLOCK_LEN]> for Block {
83 #[inline]
84 fn from(bytes: &[u8; BLOCK_LEN]) -> Self {
85 unsafe { core::mem::transmute_copy(bytes) }
86 }
87}
88
89impl AsRef<[u8; BLOCK_LEN]> for Block {
90 #[allow(clippy::transmute_ptr_to_ptr)]
91 #[inline]
92 fn as_ref(&self) -> &[u8; BLOCK_LEN] {
93 unsafe { core::mem::transmute(self) }
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100
101 #[test]
102 fn test_bitxor_assign() {
103 const ONES: u64 = -1i64 as u64;
104 const TEST_CASES: &[([u64; 2], [u64; 2], [u64; 2])] = &[
105 ([0, 0], [0, 0], [0, 0]),
106 ([0, 0], [ONES, ONES], [ONES, ONES]),
107 ([0, ONES], [ONES, 0], [ONES, ONES]),
108 ([ONES, 0], [0, ONES], [ONES, ONES]),
109 ([ONES, ONES], [ONES, ONES], [0, 0]),
110 ];
111 for (expected_result, a, b) in TEST_CASES {
112 let mut r = Block::from_u64_le(a[0].into(), a[1].into());
113 r.bitxor_assign(Block::from_u64_le(b[0].into(), b[1].into()));
114 assert_eq!(*expected_result, r.subblocks);
115
116 let mut r = Block::from_u64_le(b[0].into(), b[1].into());
118 r.bitxor_assign(Block::from_u64_le(a[0].into(), a[1].into()));
119 assert_eq!(*expected_result, r.subblocks);
120 }
121 }
122}