예제 #1
0
        private static UInt64 DifferentialTestRecursion(List <Byte[]> diffs, Hash hash, Int32 keysBytes, Byte[] k1, Byte[] k2, Int32 hashBytes, Byte[] h1, Byte[] h2, Int32 start, Int32 bitsleft)
        {
            UInt64 skipped = 0;

            for (Int32 i = start; i < (keysBytes * 8); ++i)
            {
                --bitsleft;

                BitsUtilities.FlipBit(k2, 0, keysBytes, i);

                Byte[] h = hash.ComputeHash(k2);
                UnsafeBuffer.BlockCopy(h, 0, h2, 0, hashBytes);

                if (NativeMethods.EqualSequences(h1, h2))
                {
                    if (diffs.Count < DT_MAXIMUMERRORS)
                    {
                        Byte[] diff = new Byte[keysBytes];

                        for (Int32 j = 0; j < keysBytes; ++j)
                        {
                            diff[j] = (Byte)(k1[j] ^ k2[j]);
                        }

                        diffs.Add(diff);
                    }
                    else
                    {
                        ++skipped;
                    }
                }

                if (bitsleft > 0)
                {
                    skipped += DifferentialTestRecursion(diffs, hash, keysBytes, k1, k2, hashBytes, h1, h2, i + 1, bitsleft);
                }

                BitsUtilities.FlipBit(k2, 0, keysBytes, i);

                ++bitsleft;
            }

            return(skipped);
        }
예제 #2
0
        public static void AvalancheTest(HashInfo hashInfo)
        {
            RandomXS r         = new RandomXS(0x000000B0u);
            Hash     hash      = hashInfo.Initializer(r.NextValue());
            Int32    hashBytes = hashInfo.Length / 8;
            Int32    hashBits  = hashInfo.Length;

            Console.WriteLine("[[ AVALANCHE TEST ]]");

            Boolean resultOverall = true;

            for (Int32 i = 0; i < s_ParametersAT.Length; ++i)
            {
                dynamic p = s_ParametersAT[i];

                Int32  keyBytes = p.KeysBytes;
                Int32  keyBits  = keyBytes * 8;
                Byte[] key      = new Byte[p.KeysBytes];

                Int32 repetitions = p.Repetitions;
                Int32 step        = repetitions / 10;

                Console.WriteLine($"> Keys Length: {keyBytes} Bytes");
                Console.WriteLine($"  Repetitions: {repetitions}");
                Console.Write("  Result: ");

                Int32   binsCount = keyBits * hashBits;
                Int32[] bins      = new Int32[keyBits * hashBits];

                for (Int32 j = 0; j < repetitions; ++j)
                {
                    if ((j % step) == 0)
                    {
                        Console.Write(".");
                    }

                    r.NextBytes(key);

                    Byte[] h0 = hash.ComputeHash(key);

                    Int32 binsIndex = 0;

                    for (Int32 keyBit = 0; keyBit < keyBits; ++keyBit)
                    {
                        BitsUtilities.FlipBit(key, 0, keyBytes, keyBit);
                        Byte[] hi = hash.ComputeHash(key);
                        BitsUtilities.FlipBit(key, 0, keyBytes, keyBit);

                        for (Int32 hashBit = 0; hashBit < hashBits; ++hashBit)
                        {
                            Byte a = BitsUtilities.GetBit(h0, 0, hashBytes, hashBit);
                            Byte b = BitsUtilities.GetBit(hi, 0, hashBytes, hashBit);

                            bins[binsIndex++] += a ^ b;
                        }
                    }
                }

                Double worstBias = 0.0d;

                for (Int32 j = 0; j < binsCount; ++j)
                {
                    Double c    = (Double)bins[j] / repetitions;
                    Double bias = Math.Abs((c * 2.0d) - 1.0d);

                    if (bias > worstBias)
                    {
                        worstBias = bias;
                    }
                }

                Boolean result = (worstBias <= 0.01d);
                Console.WriteLine(result ? " PASSED" : " FAILED");
                Console.WriteLine($"   - Worst Bias: {(worstBias.Equals(0.0d) ? "Unbiased" : $"{(worstBias * 100.0d):F2}%")}");

                resultOverall &= result;
            }

            Console.WriteLine($"Test Result: {(resultOverall ? "PASSED" : "FAILED")}");
        }
예제 #3
0
        public static void BitIndependenceCriterionTest(HashInfo hashInfo)
        {
            RandomXS r = new RandomXS(0x000000B1u);

            Hash  hash      = hashInfo.Initializer(r.NextValue());
            Int32 hashBytes = hashInfo.Length / 8;
            Int32 hashBits  = hashInfo.Length;
            Int32 pageSize  = hashBits * hashBits * 4;

            Int32 keyBytes = BICT_KEYSBYTES;
            Int32 keyBits  = keyBytes * 8;

            Byte[] key = new Byte[keyBytes];

            Double biasFactor = BICT_REPETITIONS / 2.0d;

            Int32 step = keyBits / 10;

            Console.WriteLine("[[ BIT INDEPENDENCE CRITERION TEST ]]");
            Console.Write("Result: ");

            Int32[] bins = new Int32[keyBits * pageSize];

            for (Int32 keyBit = 0; keyBit < keyBits; ++keyBit)
            {
                if ((keyBit % step) == 0)
                {
                    Console.Write(".");
                }

                Int32 pageOffset = keyBit * pageSize;

                for (Int32 irep = 0; irep < BICT_REPETITIONS; ++irep)
                {
                    r.NextBytes(key);

                    Byte[] h1 = hash.ComputeHash(key);
                    BitsUtilities.FlipBit(key, 0, keyBytes, keyBit);
                    Byte[] h2 = hash.ComputeHash(key);

                    Byte[] d = new Byte[hashBytes];

                    for (Int32 i = 0; i < hashBytes; ++i)
                    {
                        d[i] = (Byte)(h1[i] ^ h2[i]);
                    }

                    for (Int32 hashBit1 = 0; hashBit1 < hashBits - 1; ++hashBit1)
                    {
                        for (Int32 hashBit2 = hashBit1 + 1; hashBit2 < hashBits; ++hashBit2)
                        {
                            Int32 x = BitsUtilities.GetBit(d, 0, hashBytes, hashBit1) | (BitsUtilities.GetBit(d, 0, hashBytes, hashBit2) << 1);
                            ++bins[pageOffset + (((hashBit1 * hashBits) + hashBit2) * 4) + x];
                        }
                    }
                }
            }

            Double worstBias     = 0.0d;
            Int32  worstKeyBit   = -1;
            Int32  worstHashBit1 = -1;
            Int32  worstHashBit2 = -1;

            for (Int32 hashBit1 = 0; hashBit1 < hashBits - 1; ++hashBit1)
            {
                for (Int32 hashBit2 = hashBit1 + 1; hashBit2 < hashBits; ++hashBit2)
                {
                    for (Int32 keyBit = 0; keyBit < keyBits; ++keyBit)
                    {
                        Int32 binsOffset = (keyBit * pageSize) + ((hashBit1 * hashBits) + hashBit2) * 4;

                        for (Int32 b = 0; b < 4; ++b)
                        {
                            Double c    = bins[binsOffset + b] / biasFactor;
                            Double bias = Math.Abs((c * 2.0d) - 1.0d);

                            if (bias > worstBias)
                            {
                                worstBias     = bias;
                                worstKeyBit   = keyBit;
                                worstHashBit1 = hashBit1;
                                worstHashBit2 = hashBit2;
                            }
                        }
                    }
                }
            }

            Boolean result = (worstBias <= 0.05d);

            Console.WriteLine(result ? " PASSED" : " FAILED");
            Console.WriteLine($"  - Worst Bias: {(worstBias.Equals(0.0d) ? "Unbiased" : $"{(worstBias * 100.0d):F2}% (Key Bit: {worstKeyBit} | Hash Bit 1: {worstHashBit1} | Hash Bit 2: {worstHashBit2})")}");
        }
예제 #4
0
        public static AnalysisResult AnalyzeHashes(List <Byte[]> hashes, Int32 hashBytes)
        {
            if (hashes == null)
            {
                throw new ArgumentNullException(nameof(hashes));
            }

            Int32 hashBits = hashBytes * 8;

            Int32  hashesCount      = hashes.Count;
            Double hashesCountFloat = hashesCount;

            hashes.Sort(NativeMethods.CompareSequences);

            Double  expectedCollisions = Math.Round((hashesCountFloat * (hashesCountFloat - 1.0d)) / Math.Pow(2.0d, hashBits + 1));
            Double  observedCollisions = 0.0d;
            Boolean result             = true;

            for (Int32 i = 1; i < hashesCount; ++i)
            {
                if (NativeMethods.EqualSequences(hashes[i], hashes[i - 1]))
                {
                    ++observedCollisions;
                }
            }

            if (hashBits <= 32)
            {
                if (((observedCollisions / expectedCollisions) > 2.0d) && (Math.Abs(observedCollisions - expectedCollisions) > 1.0d))
                {
                    result = false;
                }
            }
            else if (observedCollisions > 0.0d)
            {
                result = false;
            }

            Int32 maximumLength = MAXIMUM_LENGTH;

            while ((hashesCountFloat / (1 << maximumLength)) < 5.0d)
            {
                --maximumLength;
            }

            Int32[] bins = new Int32[1 << maximumLength];

            Double worstBias   = 0.0d;
            Int32  worstBit    = -1;
            Int32  worstWindow = -1;

            for (Int32 start = 0; start < hashBits; ++start)
            {
                Int32 length    = maximumLength;
                Int32 binsCount = (1 << length);

                for (Int32 i = 0; i < binsCount; ++i)
                {
                    bins[i] = 0;
                }

                for (Int32 i = 0; i < hashesCount; ++i)
                {
                    Byte[] hash  = hashes[i];
                    Int32  index = (Int32)BitsUtilities.Window(hash, start, length);

                    ++bins[index];
                }

                while (binsCount >= 256)
                {
                    Double r = 0.0d;

                    for (Int32 i = 0; i < binsCount; ++i)
                    {
                        r += Math.Pow(bins[i], 2.0d);
                    }

                    r = Math.Sqrt(r / binsCount);

                    Double f    = (Math.Pow(hashesCount, 2.0d) - 1.0d) / ((binsCount * Math.Pow(r, 2.0d)) - hashesCount);
                    Double bias = (1.0d - (f / binsCount)) * 100.0d;

                    if (bias > worstBias)
                    {
                        worstBias   = bias;
                        worstBit    = start;
                        worstWindow = length;
                    }

                    --length;
                    binsCount /= 2;

                    if (length < 8)
                    {
                        break;
                    }

                    for (Int32 i = 0; i < binsCount; ++i)
                    {
                        bins[i] += bins[binsCount + i];
                    }
                }
            }

            return(new AnalysisResult
            {
                Outcome = result,
                HashesCount = hashesCount,
                ExpectedCollisions = expectedCollisions,
                ObservedCollisions = observedCollisions,
                WorstBias = worstBias,
                WorstBit = worstBit,
                WorstWindow = worstWindow
            });
        }