1
1
//! [Day 14: One-Time Pad](https://adventofcode.com/2016/day/14)
2
2
3
3
use rustc_hash:: FxHashMap ;
4
- // use std::time::Instant;
5
4
6
5
/// Solve the day 14 puzzle.
7
6
fn main ( ) {
8
7
let args = aoc:: parse_args ( ) ;
9
8
10
9
let data = args. input . trim_ascii ( ) ;
11
10
12
- // let now = Instant::now();
13
-
14
- println ! ( "{}" , solve( data, 0 ) ) ;
15
- println ! ( "{}" , solve( data, 2016 ) ) ;
16
-
17
- // let micros = now.elapsed().as_micros();
18
- // println!("elapsed: {}.{:06} s", micros / 1_000_000, micros % 1_000_000);
11
+ println ! ( "{}" , solve( data. as_bytes( ) , 0 ) ) ;
12
+ println ! ( "{}" , solve( data. as_bytes( ) , 2016 ) ) ;
19
13
}
20
14
15
+ const HEX_DIGITS : [ u8 ; 16 ] = [
16
+ b'0' , b'1' , b'2' , b'3' , b'4' , b'5' , b'6' , b'7' , b'8' , b'9' , b'a' , b'b' , b'c' , b'd' , b'e' , b'f' ,
17
+ ] ;
18
+
21
19
/// Triplet for a given index.
22
20
#[ derive( Debug , Clone , Copy ) ]
23
21
struct TripletHash {
24
- index : usize , // index that produces hash with triplet
22
+ index : u32 , // index that produces hash with triplet
25
23
triplet : u8 , // the first triplet of the hash
26
24
quintuplet : [ u8 ; 6 ] , // six quintuplets max in 32 digits
27
25
}
@@ -30,16 +28,47 @@ impl TripletHash {
30
28
/// Find the next index that produces a hash that contains a triplet
31
29
/// and search for eventual quintuplets. As quintuplets are also triplets,
32
30
/// we cannot miss them.
33
- fn next ( index : usize , salt : & str , key_stretching : usize ) -> Self {
31
+ fn next ( index : u32 , salt : & [ u8 ] , key_stretching : u32 ) -> Self {
34
32
let mut index = index;
35
33
34
+ let salt_len = salt. len ( ) ;
35
+ let mut hash = [ 0u8 ; 32 ] ;
36
+
37
+ hash[ ..salt_len] . copy_from_slice ( salt) ;
38
+
36
39
loop {
37
- let hash = format ! ( "{salt}{index}" ) ;
38
- let mut digest = md5:: compute ( hash) ;
40
+ // number of digits of index
41
+ let mut hash_len = salt_len;
42
+ let mut tmp_index = index;
43
+ loop {
44
+ hash_len += 1 ;
45
+ tmp_index /= 10 ;
46
+ if tmp_index == 0 {
47
+ break ;
48
+ }
49
+ }
50
+ // write digits of index in hash
51
+ let mut tmp_index = index;
52
+ let mut i = hash_len;
53
+ loop {
54
+ i -= 1 ;
55
+ hash[ i] = ( tmp_index % 10 ) as u8 + b'0' ;
56
+ tmp_index /= 10 ;
57
+ if tmp_index == 0 {
58
+ break ;
59
+ }
60
+ }
61
+
62
+ let mut digest = md5:: compute ( & hash[ ..hash_len] ) ;
39
63
40
64
// apply key stretching
41
65
for _ in 0 ..key_stretching {
42
- let hex = format ! ( "{digest:x}" ) ;
66
+ let mut hex = [ 0u8 ; 32 ] ;
67
+ for ( i, b) in digest. 0 . iter ( ) . enumerate ( ) {
68
+ hex[ i * 2 ] = HEX_DIGITS [ usize:: from ( b >> 4 ) ] ;
69
+ hex[ i * 2 + 1 ] = HEX_DIGITS [ usize:: from ( b & 0xf ) ] ;
70
+ }
71
+
43
72
digest = md5:: compute ( hex) ;
44
73
}
45
74
@@ -96,7 +125,7 @@ impl TripletHash {
96
125
}
97
126
98
127
/// Find the 64th key with the given salt and key stretching.
99
- fn solve ( salt : & str , key_stretching : usize ) -> usize {
128
+ fn solve ( salt : & [ u8 ] , key_stretching : u32 ) -> u32 {
100
129
let mut memoize = FxHashMap :: default ( ) ;
101
130
102
131
let mut hasher = |index| {
@@ -142,7 +171,7 @@ fn solve(salt: &str, key_stretching: usize) -> usize {
142
171
143
172
#[ test]
144
173
fn test_solve1 ( ) {
145
- assert_eq ! ( solve( "abc" , 0 ) , 22728 ) ;
174
+ assert_eq ! ( solve( "abc" . as_bytes ( ) , 0 ) , 22728 ) ;
146
175
}
147
176
148
177
#[ test]
0 commit comments