1use std::{io::Error, io::ErrorKind};
2
3use wide::u64x8;
4
5pub mod benchmark;
6
7pub const ALL_ONES: u64x8 = u64x8::splat(0xFFFFFFFFFFFFFFFF);
8pub const ZERO: u64x8 = u64x8::ZERO;
9
10pub fn splat(n: u64) -> u64x8 {
11 u64x8::splat(n)
12}
13
14pub fn bitsliced_add(a: &[u64x8; 64], b: &[u64x8; 64]) -> [u64x8; 64] {
17 let mut carry = u64x8::ZERO;
18 let mut sum = [u64x8::ZERO; 64];
19 for i in (0..64).rev() {
20 let res = calc_sum_carry(a[i], b[i], carry);
21 sum[i] = res.0;
22 carry = res.1;
24 }
25 sum
26}
27
28pub fn bitsliced_add_single(a: &[u64x8; 64], b: u64) -> [u64x8; 64] {
29 let mut carry = u64x8::ZERO;
30 let mut sum = [u64x8::ZERO; 64];
31 for i in (0..64).rev() {
32 let shift_right = 63 - i;
33 let current_bit = (b >> shift_right) & 1;
34 let b_i = if current_bit == 1 { ALL_ONES } else { ZERO };
35 let res = calc_sum_carry(a[i], b_i, carry);
36 sum[i] = res.0;
37 carry = res.1;
39 }
40 sum
41}
42
43pub fn bitsliced_add_inline(a: &mut [u64x8; 64], b: &[u64x8; 64]) {
44 let mut carry = u64x8::ZERO;
45 for i in (0..64).rev() {
46 let res = calc_sum_carry(a[i], b[i], carry);
47 a[i] = res.0;
48 carry = res.1;
50 }
51}
52
53pub fn bitsliced_add_single_inline(a: &mut [u64x8; 64], b: u64) {
54 let mut carry = u64x8::ZERO;
55 for i in (0..64).rev() {
56 let shift_right = 63 - i;
57 let current_bit = (b >> shift_right) & 1;
58 let b_i = if current_bit == 1 { ALL_ONES } else { ZERO };
59 let res = calc_sum_carry(a[i], b_i, carry);
60 a[i] = res.0;
61 carry = res.1;
63 }
64}
65
66fn calc_sum_carry(a: u64x8, b: u64x8, carry: u64x8) -> (u64x8, u64x8) {
67 let sum = a ^ b ^ carry;
68 let next_carry = (a & b) | (carry & (a ^ b));
69 (sum, next_carry)
70}
71
72pub fn bitsliced_modulo_power_of_two(a: &[u64x8; 64], k: usize) -> Result<[u64x8; 64], Error> {
76 if k > 64 {
77 return Err(Error::new(
78 ErrorKind::InvalidData,
79 "k must be <= 64 for bitsliced modulo",
80 ));
81 }
82 let mut out = [u64x8::splat(0); 64];
83 let start: usize = 64 - k;
84 out[start..].copy_from_slice(&a[start..]);
85
86 Ok(out)
87}
88
89pub fn bitsliced_modulo_power_of_two_inline(a: &mut [u64x8; 64], k: usize) -> Result<(), Error> {
90 if k > 64 {
91 return Err(Error::new(
92 ErrorKind::InvalidData,
93 "k must be <= 64 for bitsliced modulo",
94 ));
95 }
96 let end: usize = 64 - k;
97 for i in 0..end {
98 a[i] = u64x8::splat(0);
99 }
100
101 Ok(())
102}
103
104pub fn des_reduction(h: &[u64x8; 64], i: u64) -> [u64x8; 64] {
107 let mut sum = bitsliced_add_single(h, i);
108 bitsliced_modulo_power_of_two_inline(&mut sum, 56).unwrap();
109 sum
110}
111
112pub fn des_reduction_inline(h: &mut [u64x8; 64], i: u64) {
113 bitsliced_add_single_inline(h, i);
114 bitsliced_modulo_power_of_two_inline(h, 56).unwrap();
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120
121 #[test]
122 fn test_add_works() {
123 let mut a = [ZERO; 64];
124 a[63] = ALL_ONES;
125 let mut b = [ZERO; 64];
126 b[63] = ALL_ONES;
127 let sum = bitsliced_add(&a, &b);
128 assert_eq!(sum[63], ZERO);
129 assert_eq!(sum[62], ALL_ONES);
130 for i in 0..62 {
131 assert_eq!(sum[i], ZERO);
132 }
133 }
134
135 #[test]
136 fn test_add_single_works() {
137 let mut a = [ZERO; 64];
138 a[63] = ALL_ONES;
139 let sum = bitsliced_add_single(&a, 1);
140 assert_eq!(sum[63], ZERO);
141 assert_eq!(sum[62], ALL_ONES);
142 for i in 0..62 {
143 assert_eq!(sum[i], ZERO);
144 }
145 }
146
147 #[test]
148 fn test_add_inline_works() {
149 let mut a = [ZERO; 64];
150 a[63] = ALL_ONES;
151 let mut b = [ZERO; 64];
152 b[63] = ALL_ONES;
153 bitsliced_add_inline(&mut a, &b);
154 assert_eq!(a[63], ZERO);
155 assert_eq!(a[62], ALL_ONES);
156 for i in 0..62 {
157 assert_eq!(a[i], ZERO);
158 }
159 }
160
161 #[test]
162 fn test_add_single_inline_works() {
163 let mut a = [ZERO; 64];
164 a[63] = ALL_ONES;
165 bitsliced_add_single_inline(&mut a, 1);
166 assert_eq!(a[63], ZERO);
167 assert_eq!(a[62], ALL_ONES);
168 for i in 0..62 {
169 assert_eq!(a[i], ZERO);
170 }
171 }
172
173 #[test]
174 fn test_modulo_works() {
175 let a = [ALL_ONES; 64];
176 let res = bitsliced_modulo_power_of_two(&a, 56).unwrap();
177 for i in 0..8 {
178 assert_eq!(res[i], ZERO);
179 }
180 for i in 8..64 {
181 assert_eq!(res[i], ALL_ONES);
182 }
183 }
184
185 #[test]
186 fn test_modulo_inline_works() {
187 let mut a = [ALL_ONES; 64];
188 let _ = bitsliced_modulo_power_of_two_inline(&mut a, 56).unwrap();
189 for i in 0..8 {
190 assert_eq!(a[i], ZERO);
191 }
192 for i in 8..64 {
193 assert_eq!(a[i], ALL_ONES);
194 }
195 }
196}