private bool checkCycle() { var _logger = Log.ForContext <Share>(); if (Cycle.Length != CYCLE_LENGTH) { return(false); } var blakeHash = new HMACBlake2B(256); byte[] keys = blakeHash.ComputeHash(Encoding.ASCII.GetBytes(BlockHash.ToHexString())); UInt64 k0 = (UInt64)BitConverter.ToInt64(keys.Slice(0, 8), 0).LittleEndian(); UInt64 k1 = (UInt64)BitConverter.ToInt64(keys.Slice(8, 16), 0).LittleEndian(); UInt32 edgeMask = (UInt32)(1 << Job.EdgeBits) - 1; UInt32[] uvs = new UInt32[2 * CYCLE_LENGTH]; UInt32 xor0 = 0; UInt32 xor1 = 0; for (var n = 0; n < CYCLE_LENGTH; n++) { if (Cycle[n] > edgeMask) { _logger.Error("POW_TOO_BIG"); return(false); } if (n > 0 && Cycle[n] <= Cycle[n - 1]) { _logger.Error("POW_TOO_SMALL"); return(false); } xor0 ^= uvs[2 * n] = sipnode(k0, k1, edgeMask, Cycle[n], 0); xor1 ^= uvs[2 * n + 1] = sipnode(k0, k1, edgeMask, Cycle[n], 1); } // matching endpoints imply zero xors if ((xor0 | xor1) != 0) { var cycleStr = ""; foreach (var edge in Cycle) { cycleStr += edge.ToString("x") + ","; } cycleStr = cycleStr.Remove(cycleStr.Length - 1); _logger.Debug("Block hash: {0}", BlockHash.ToHexString()); _logger.Debug("Cycle: {0}", cycleStr); _logger.Error("POW_NON_MATCHING"); return(false); } int m = 0, i = 0, j; do // follow cycle { for (int k = j = i; (k = (k + 2) % (2 * CYCLE_LENGTH)) != i;) { if (uvs[k] == uvs[i]) // find other edge endpoint identical to one at i { if (j != i) // already found one before { _logger.Error("POW_BRANCH"); return(false); } j = k; } } if (j == i) { _logger.Error("POW_DEAD_END"); return(false); } i = j ^ 1; m++; } while (i != 0); // must cycle back to start or we would have found branch if (m != CYCLE_LENGTH) { _logger.Error("POW_SHORT_CYCLE"); return(false); } return(true); }