blob: 0232ff852d84fb4368056d54ccb4af7e36091168 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
#r "nuget: FSharpx.Collections, 3.0.1"
open System.Security.Cryptography
open System.Text
open FSharpx.Collections
let salt = "yjdafjpo"
let md5 (data: string): string =
use md5 = MD5.Create()
(StringBuilder (), md5.ComputeHash(Encoding.ASCII.GetBytes data))
||> Array.fold (fun sb b -> sb.Append(b.ToString("x2")))
|> string
// returns Some char being repeated for n many times in input hash, otherwise None if no repetitions
let getSameChar (n: int) (hash: string) : char option =
let sameChar (window: char array): char =
Array.reduce (fun x y -> if x = y then y else char 0) window
hash
|> Seq.windowed n
|> Seq.map sameChar
|> Seq.filter (fun x -> x <> char 0)
|> Seq.toArray
|> fun x -> if x.Length > 0 then Some x[0] else None
// returns true if any of the hashes contain ch repeated 5 times
let hashRepeats (ch: char) (hashes: Deque<string>): bool =
Seq.map (getSameChar 5) hashes
|> Seq.filter (function | Some x -> x = ch | None -> false)
|> fun x -> Seq.length x > 0
// hashes contains hash of salt + index, plus the next 1000 hashes
let rec getPadKey (currInd: int) (indices: int list) (hashes: Deque<string>) (hashfunc: string -> string) =
if indices.Length = 64 then indices.Head
else
let current, rest = hashes.Uncons
let hasMatch =
match getSameChar 3 current with
| Some x -> hashRepeats x rest
| None -> false
let newHashes = rest.Conj <| hashfunc (salt + string (currInd + 1001))
if hasMatch then
getPadKey (currInd + 1) (currInd::indices) newHashes hashfunc
else
getPadKey (currInd + 1) indices newHashes hashfunc
let part1hash = md5
let part2hash =
seq { for n in 0..2016 do yield md5 }
|> Seq.reduce (>>)
// part 1
let p1first1000 = Deque.ofList [ for i in 0..1000 do yield part1hash (salt + string i) ]
getPadKey 0 [] p1first1000 part1hash |> printfn "%d"
// part 2
let p2first1000 = Deque.ofList [ for i in 0..1000 do yield part2hash (salt + string i) ]
getPadKey 0 [] p2first1000 part2hash |> printfn "%d"
|