private static string Part2(long worksize, int nZeros, int passwordLength) { Dictionary <int, Tuple <long, string> > hashes = new Dictionary <int, Tuple <long, string> >(); int hashesFound = 0; long largestIndex = 0; string zeros = new string('0', nZeros); bool done = false; Thread hacking = new Thread(() => HackingPart2(ref done, passwordLength, hashes)); hacking.Start(); Parallel.ForEach(MD5Ext.YieldWhile(() => hashesFound < passwordLength, i => Tuple.Create(i * worksize, (i + 1) * worksize)), bound => { MD5 md5 = MD5.Create(); long lowerbound = bound.Item1, upperbound = bound.Item2; for (long index = lowerbound; index < upperbound && (hashesFound < passwordLength || index < Interlocked.Read(ref largestIndex)); index++) { string hash = md5.ComputeHash(Encoding.ASCII.GetBytes(DoorID + index)).MD5String(); if (hash.StartsWith(zeros)) { int key = Convert.ToInt32(hash.Substring(5, 1), 16); if (key < passwordLength) { lock (hashes) { bool contains = hashes.ContainsKey(key); if (!contains || hashes[key].Item1 > index - 1) { hashes[key] = Tuple.Create(index - 1, hash); Monitor.Pulse(hashes); if (index - 1 > Interlocked.Read(ref largestIndex)) { Interlocked.Exchange(ref largestIndex, index - 1); } if (!contains) { Interlocked.Increment(ref hashesFound); } } } } } } }); lock (hashes) { done = true; Monitor.Pulse(hashes); } hacking.Join(); return(new string(hashes.Take(passwordLength).OrderBy(hash => hash.Key).Select(hash => hash.Value.Item2[6]).ToArray())); }
// Calculate part 1 in parallel private static string Part1(long worksize, int nZeros, int passwordLength) { SortedList <long, string> hashes = new SortedList <long, string>(); int hashesFound = 0; long largestIndex = 0; string zeros = new string('0', nZeros); bool done = false; Thread hacking = new Thread(() => HackingPart1(ref done, passwordLength, hashes)); hacking.Start(); Parallel.ForEach(MD5Ext.YieldWhile(() => hashesFound < passwordLength, i => Tuple.Create(i * worksize, (i + 1) * worksize)), bound => { MD5 md5 = MD5.Create(); long lowerbound = bound.Item1, upperbound = bound.Item2; for (long index = lowerbound; index < upperbound && (hashesFound < passwordLength || index < Interlocked.Read(ref largestIndex)); index++) { string hash = md5.ComputeHash(Encoding.ASCII.GetBytes(DoorID + index)).MD5String(); if (hash.StartsWith(zeros)) { lock (hashes) { hashes.Add(index - 1, hash); Monitor.Pulse(hashes); if (index - 1 > largestIndex) { largestIndex = index - 1; } Interlocked.Increment(ref hashesFound); } } } }); lock (hashes) { done = true; Monitor.Pulse(hashes); } hacking.Join(); return(new string(hashes.Take(passwordLength).Select(hash => hash.Value[5]).ToArray())); }