1use core::fmt::NumBuffer;
6use std::collections::{BTreeMap, BTreeSet};
7use std::sync::Mutex;
8
9use self::implementation::*;
10use crate::util::md5::*;
11use crate::util::thread::*;
12
13struct Shared {
15 input: String,
16 part_two: bool,
17 iter: AtomicIter,
18 mutex: Mutex<Exclusive>,
19}
20
21struct Exclusive {
23 threes: BTreeMap<i32, u32>,
24 fives: BTreeMap<i32, u32>,
25 found: BTreeSet<i32>,
26}
27
28pub fn parse(input: &str) -> &str {
29 input.trim()
30}
31
32pub fn part1(input: &str) -> i32 {
34 generate_pad(input, false)
35}
36
37pub fn part2(input: &str) -> i32 {
39 generate_pad(input, true)
40}
41
42fn generate_pad(input: &str, part_two: bool) -> i32 {
44 let step = if cfg!(feature = "simd") { 32 } else { 1 };
45 let input = input.to_owned();
46
47 let exclusive =
48 Exclusive { threes: BTreeMap::new(), fives: BTreeMap::new(), found: BTreeSet::new() };
49 let shared =
50 Shared { input, part_two, iter: AtomicIter::new(0, step), mutex: Mutex::new(exclusive) };
51
52 spawn(|| worker(&shared));
54
55 let exclusive = shared.mutex.into_inner().unwrap();
56 *exclusive.found.iter().nth(63).unwrap()
57}
58
59fn format_string(prefix: &str, n: i32) -> ([u8; 64], usize) {
61 let mut number = NumBuffer::new();
62 let digits = n.format_into(&mut number).as_bytes();
63 let size = prefix.len() + digits.len();
64
65 let mut buffer = [0; 64];
66 buffer[..prefix.len()].copy_from_slice(prefix.as_bytes());
67 buffer[prefix.len()..size].copy_from_slice(digits);
68
69 (buffer, size)
70}
71
72#[inline]
74fn to_ascii(n: u32) -> [u8; 8] {
75 let mut n = u64::from(n);
77 n = ((n << 16) & 0x0000ffff00000000) | (n & 0x000000000000ffff);
78 n = ((n << 8) & 0x00ff000000ff0000) | (n & 0x000000ff000000ff);
79 n = ((n << 4) & 0x0f000f000f000f00) | (n & 0x000f000f000f000f);
80
81 let mask = ((n + 0x0606060606060606) >> 4) & 0x0101010101010101;
91 n = n + 0x3030303030303030 + 0x27 * mask;
92 n.to_be_bytes()
93}
94
95#[cfg(not(feature = "simd"))]
96mod implementation {
97 use super::*;
98
99 pub(super) fn worker(shared: &Shared) {
100 while let Some(n) = shared.iter.next() {
101 let n = n as i32;
103
104 let (mut buffer, size) = format_string(&shared.input, n);
106 let mut result = hash(&mut buffer, size);
107
108 if shared.part_two {
109 for _ in 0..2016 {
110 buffer[0..8].copy_from_slice(&to_ascii(result[0]));
111 buffer[8..16].copy_from_slice(&to_ascii(result[1]));
112 buffer[16..24].copy_from_slice(&to_ascii(result[2]));
113 buffer[24..32].copy_from_slice(&to_ascii(result[3]));
114 result = hash(&mut buffer, 32);
115 }
116 }
117
118 check(shared, n, result);
119 }
120 }
121
122 fn check(shared: &Shared, n: i32, hash: [u32; 4]) {
124 let [a, b, c, d] = hash;
125
126 let mut prev = u32::MAX;
127 let mut same = 1;
128 let mut three = 0;
129 let mut five = 0;
130
131 for mut word in [d, c, b, a] {
132 for _ in 0..8 {
133 let next = word & 0xf;
134
135 same = if next == prev { same + 1 } else { 1 };
136
137 if same == 3 {
138 three = 1 << next;
139 }
140 if same == 5 {
141 five |= 1 << next;
142 }
143
144 word >>= 4;
145 prev = next;
146 }
147 }
148
149 if three != 0 || five != 0 {
150 let mut exclusive = shared.mutex.lock().unwrap();
151 let mut candidates = Vec::new();
152
153 if three != 0 {
155 exclusive.threes.insert(n, three);
156
157 for (_, mask) in exclusive.fives.range(n + 1..n + 1001) {
158 if three & mask != 0 {
159 candidates.push(n);
160 }
161 }
162 }
163
164 if five != 0 {
166 exclusive.fives.insert(n, five);
167
168 for (&index, &mask) in exclusive.threes.range(n - 1000..n) {
169 if five & mask != 0 {
170 candidates.push(index);
171 }
172 }
173 }
174
175 exclusive.found.extend(candidates);
177
178 if exclusive.found.len() >= 64 {
179 shared.iter.stop();
180 }
181 }
182 }
183}
184
185#[cfg(feature = "simd")]
186mod implementation {
187 use std::simd::prelude::*;
188
189 use super::*;
190 use crate::util::bitset::*;
191 use crate::util::md5::simd::hash_fixed;
192
193 pub(super) fn worker(shared: &Shared) {
195 let mut result = [Simd::splat(0); 4];
196 let mut buffers = [[0; 64]; 32];
197
198 while let Some(start) = shared.iter.next() {
199 let start = start as i32;
201
202 for i in 0..32 {
204 let (mut buffer, size) = format_string(&shared.input, start + i as i32);
205 let [a, b, c, d] = hash(&mut buffer, size);
206
207 result[0][i] = a;
208 result[1][i] = b;
209 result[2][i] = c;
210 result[3][i] = d;
211 }
212
213 if shared.part_two {
214 for _ in 0..2016 {
215 for i in 0..32 {
216 buffers[i][0..8].copy_from_slice(&to_ascii(result[0][i]));
217 buffers[i][8..16].copy_from_slice(&to_ascii(result[1][i]));
218 buffers[i][16..24].copy_from_slice(&to_ascii(result[2][i]));
219 buffers[i][24..32].copy_from_slice(&to_ascii(result[3][i]));
220 }
221 result = hash_fixed(&mut buffers, 32);
222 }
223 }
224
225 check(shared, start, &result);
226 }
227 }
228
229 #[inline]
231 fn check(shared: &Shared, start: i32, hash: &[Simd<u32, 32>; 4]) {
232 let &[a, b, c, d] = hash;
233
234 let mut prev: Simd<u32, 32> = Simd::splat(u32::MAX);
235 let mut same: Simd<u32, 32> = Simd::splat(1);
236 let mut three: Simd<u32, 32> = Simd::splat(0);
237 let mut five: Simd<u32, 32> = Simd::splat(0);
238
239 for mut word in [d, c, b, a] {
240 for _ in 0..8 {
241 let next = word & Simd::splat(0xf);
242 same = next.simd_eq(prev).select(same + Simd::splat(1), Simd::splat(1));
243
244 three = same.simd_eq(Simd::splat(3)).select(Simd::splat(1) << next, three);
245 five |= same.simd_eq(Simd::splat(5)).select(Simd::splat(1) << next, Simd::splat(0));
246
247 word >>= 4;
248 prev = next;
249 }
250 }
251
252 let three_mask = three.simd_ne(Simd::splat(0)).to_bitmask();
253 let five_mask = five.simd_ne(Simd::splat(0)).to_bitmask();
254
255 if three_mask != 0 || five_mask != 0 {
256 let mut exclusive = shared.mutex.lock().unwrap();
257 let mut candidates = Vec::new();
258
259 for i in three_mask.biterator() {
260 let three = three[i];
261 let n = start + i as i32;
262
263 if three != 0 {
265 exclusive.threes.insert(n, three);
266
267 for (_, mask) in exclusive.fives.range(n + 1..n + 1001) {
268 if three & mask != 0 {
269 candidates.push(n);
270 }
271 }
272 }
273 }
274
275 for i in five_mask.biterator() {
276 let five = five[i];
277 let n = start + i as i32;
278
279 if five != 0 {
281 exclusive.fives.insert(n, five);
282
283 for (&index, &mask) in exclusive.threes.range(n - 1000..n) {
284 if five & mask != 0 {
285 candidates.push(index);
286 }
287 }
288 }
289 }
290
291 exclusive.found.extend(candidates);
293
294 if exclusive.found.len() >= 64 {
295 shared.iter.stop();
296 }
297 }
298 }
299}