private static void CombinationCount(ReadablePassphraseGenerator generator)
        {
            Console.WriteLine();
            Console.WriteLine("Combination count:");

            foreach (var strength in RandomStrengths)
            {
                var combinations = generator.CalculateCombinations(strength);
                Console.WriteLine("  {0}: {1:E3} ({2:N2} bits)", strength, combinations.ToString(), combinations.EntropyBitsToString());
            }
            Console.WriteLine();

            var predefined = new PhraseStrength[]
            {
                PhraseStrength.Normal, PhraseStrength.NormalAnd, PhraseStrength.NormalSpeech, PhraseStrength.NormalEqual, PhraseStrength.NormalEqualAnd, PhraseStrength.NormalEqualSpeech, PhraseStrength.NormalRequired, PhraseStrength.NormalRequiredAnd, PhraseStrength.NormalRequiredSpeech,
                PhraseStrength.Strong, PhraseStrength.StrongAnd, PhraseStrength.StrongSpeech, PhraseStrength.StrongEqual, PhraseStrength.StrongEqualAnd, PhraseStrength.StrongEqualSpeech, PhraseStrength.StrongRequired, PhraseStrength.StrongRequiredAnd, PhraseStrength.StrongRequiredSpeech,
                PhraseStrength.Insane, PhraseStrength.InsaneAnd, PhraseStrength.InsaneSpeech, PhraseStrength.InsaneEqual, PhraseStrength.InsaneEqualAnd, PhraseStrength.InsaneEqualSpeech, PhraseStrength.InsaneRequired, PhraseStrength.InsaneRequiredAnd, PhraseStrength.InsaneRequiredSpeech,
            };

            for (int i = 0; i < predefined.Length; i++)
            {
                var strength     = predefined[i];
                var combinations = generator.CalculateCombinations(strength);
                Console.WriteLine("  {0}: {1:E3} ({2:N2} bits)", strength, combinations.ToString(), combinations.EntropyBitsToString());
                if ((i + 1) % 9 == 0)
                {
                    Console.WriteLine();
                }
            }
        }
 private static void TinkerWithCustomClause(ReadablePassphraseGenerator generator)
 {
     GenerateCustomSamples(new Clause[]
     {
         new NounClause()
         {
             CommonNounFactor    = 1, ProperNounFactor = 0, NounFromAdjectiveFactor = 0,
             SingularityFactor   = 1, PluralityFactor = 1,
             NoArticleFactor     = 1, DefiniteArticleFactor = 1, IndefiniteArticleFactor = 1, DemonstractiveFactor = 1, PersonalPronounFactor = 1,
             NoNumberFactor      = 1, NumberFactor = 1,
             NoAdjectiveFactor   = 1, AdjectiveFactor = 0,
             NoPrepositionFactor = 1, PrepositionFactor = 0
         },
         new VerbClause()
         {
             PresentFactor                    = 1, PastFactor = 1, FutureFactor = 1, ContinuousFactor = 1, ContinuousPastFactor = 1, PerfectFactor = 1, SubjunctiveFactor = 1,
             NoAdverbFactor                   = 1, AdverbFactor = 0,
             NoInterrogativeFactor            = 1, InterrogativeFactor = 0,
             IntransitiveByNoNounClauseFactor = 1, IntransitiveByPrepositionFactor = 1
         },
         new NounClause()
         {
             CommonNounFactor    = 1, ProperNounFactor = 0, NounFromAdjectiveFactor = 0,
             SingularityFactor   = 1, PluralityFactor = 1,
             NoArticleFactor     = 1, DefiniteArticleFactor = 1, IndefiniteArticleFactor = 1, DemonstractiveFactor = 1, PersonalPronounFactor = 1,
             NoNumberFactor      = 1, NumberFactor = 0,
             NoAdjectiveFactor   = 1, AdjectiveFactor = 0,
             NoPrepositionFactor = 1, PrepositionFactor = 0
         },
     }
                           , generator, 100);
 }
        private static void DictionaryCheck(ReadablePassphraseGenerator generator)
        {
            Console.WriteLine();
            Console.WriteLine("Name: {0}", generator.Dictionary.Name);
            Console.WriteLine("Langauge: {0}", generator.Dictionary.LanguageCode);
            Console.WriteLine("TOTAL:           {0:N0}", generator.Dictionary.Count);
            Console.WriteLine("TOTAL forms:     {0:N0}", generator.Dictionary.CountOfAllDistinctForms());
            Console.WriteLine("Nouns:           {0:N0}", generator.Dictionary.OfType <Noun>().Count());
            Console.WriteLine("Proper Nouns:    {0:N0}", generator.Dictionary.OfType <ProperNoun>().Count());
            Console.WriteLine("Verbs (all):     {0:N0}", generator.Dictionary.OfType <Verb>().Count());
            Console.WriteLine("Verbs (trans):   {0:N0}", generator.Dictionary.OfType <Verb>().Count(w => w.IsTransitive));
            Console.WriteLine("Verbs (intrans): {0:N0}", generator.Dictionary.OfType <Verb>().Count(w => !w.IsTransitive));
            Console.WriteLine("Prepositions:    {0:N0}", generator.Dictionary.OfType <Preposition>().Count());
            Console.WriteLine("Adverbs:         {0:N0}", generator.Dictionary.OfType <Adverb>().Count());
            Console.WriteLine("Adjectives:      {0:N0}", generator.Dictionary.OfType <Adjective>().Count());

            // Check for duplicates.
            foreach (var t in typeof(Word).Assembly.GetTypes().Where(t => typeof(Word).IsAssignableFrom(t) && t != typeof(Word)))
            {
                var duplicates = generator.Dictionary
                                 .Where(w => t.IsAssignableFrom(w.GetType()))
                                 .GroupBy(w => w.DictionaryEntry, StringComparer.OrdinalIgnoreCase)
                                 .Where(g => g.Count() > 1);
                if (duplicates.Any())
                {
                    Console.WriteLine("DUPLICATES for {0}:", t.Name);
                    foreach (var g in duplicates)
                    {
                        Console.WriteLine("    - " + g.Key);
                    }
                }
            }
        }
 private static void TestGenerationAsSecure(ReadablePassphraseGenerator generator, IEnumerable <PhraseStrength> strengths, int iterations)
 {
     Console.Write("Testing {0:N0} secure phrases of strength {1}...", iterations, String.Join(",", strengths.Select(x => x.ToString())));
     for (int i = 0; i < iterations; i++)
     {
         generator.GenerateAsSecure(strengths);
     }
     Console.WriteLine(" OK.");
 }
 private static void GenerateSamples(PhraseStrength strength, ReadablePassphraseGenerator generator, int count)
 {
     Console.WriteLine();
     Console.WriteLine("Samples:");
     for (int i = 0; i < count; i++)
     {
         Console.WriteLine(generator.Generate(strength));
     }
 }
 private static void GenerateDelimiterSamples(PhraseStrength strength, ReadablePassphraseGenerator generator, int count, string delimiter)
 {
     Console.WriteLine();
     Console.WriteLine("Delimited Samples ('{0}'):", delimiter);
     for (int i = 0; i < count; i++)
     {
         Console.WriteLine(generator.Generate(strength, wordDelimiter: delimiter));
     }
 }
 private static void TestGenerationAsSecure(ReadablePassphraseGenerator generator, PhraseStrength strength, int iterations)
 {
     Console.Write("Testing {0:N0} secure phrases of strength {1}...", iterations, strength);
     for (int i = 0; i < iterations; i++)
     {
         generator.GenerateAsSecure(strength);
     }
     Console.WriteLine(" OK.");
 }
 private static void GenerateMutatedSamples(PhraseStrength strength, ReadablePassphraseGenerator generator, int count, IEnumerable <IMutator> mutators)
 {
     Console.WriteLine();
     Console.WriteLine("Mutated Samples:");
     for (int i = 0; i < count; i++)
     {
         var passphrase = generator.Generate(strength, mutators: mutators);
         Console.WriteLine(passphrase);
     }
 }
        private static void BenchmarkUtf8Generation(ReadablePassphraseGenerator generator, PhraseStrength strength, int iterations)
        {
            Console.WriteLine();
            Console.WriteLine("Benchmark of {0:N0} UTF8 phrases of strength {1}...", iterations, strength);
            var sw = System.Diagnostics.Stopwatch.StartNew();

            for (int i = 0; i < iterations; i++)
            {
                generator.GenerateAsUtf8Bytes(strength);
            }
            sw.Stop();
            Console.WriteLine("  in {0:N3}ms", sw.Elapsed.TotalMilliseconds);
        }
        private static void WriteAllStatistics(ReadablePassphraseGenerator generator)
        {
            System.IO.File.Delete(AllStatsCharFilename);
            var specialStrengths = RandomStrengths.Concat(new[] { PhraseStrength.Custom });
            var allToTest        = Enum.GetValues(typeof(PhraseStrength)).Cast <PhraseStrength>()
                                   .Where(x => !specialStrengths.Contains(x));

            foreach (var strength in allToTest)
            {
                WriteStatisticsFor(generator, strength, 1000000, strength.ToString() + ".csv");
            }
            foreach (var strength in RandomStrengths)
            {
                WriteStatisticsFor(generator, strength, 10000000, strength.ToString() + ".csv");
            }
        }
        private static void TestConfigForm(ReadablePassphraseGenerator generator)
        {
            String config;

            using (var frm = new KeePassReadablePassphrase.ConfigRoot("", GetRandomness()))
            {
                frm.ShowDialog();
                Console.WriteLine();
                Console.WriteLine("Serialised Config from Form:");
                Console.WriteLine(frm.ConfigForKeePass);
                config = frm.ConfigForKeePass;
            }
            using (var frm = new KeePassReadablePassphrase.ConfigRoot(config, GetRandomness()))
            {
                frm.ShowDialog();
            }
        }
        private static void TestTextualParsing(ReadablePassphraseGenerator generator, PhraseStrength strength)
        {
            Console.WriteLine("Testing parsing of textual phrase strength {0}...", strength);
            var description = Clause.CreatePhraseDescription(strength, generator.Randomness);
            var sb          = new StringBuilder();

            foreach (var c in description)
            {
                c.ToStringBuilder(sb);
            }
            var textualDescription = sb.ToString();

            Console.Write("    Generation OK.");
            var customStrength = Clause.CreateCollectionFromTextString(textualDescription);

            Console.Write(" Parsing OK.");
            generator.Generate(customStrength);
            Console.WriteLine(" Passphrase OK.");
        }
        private static void TestAllStrengthsAndOutputs(ReadablePassphraseGenerator generator)
        {
            var specialStrengths = RandomStrengths.Concat(new[] { PhraseStrength.Custom });
            var allToTest        = Enum.GetValues(typeof(PhraseStrength)).Cast <PhraseStrength>()
                                   .Where(x => !specialStrengths.Contains(x));

            foreach (var strength in allToTest)
            {
                TestTextualParsing(generator, strength);
                TestGeneration(generator, strength, 50);
                TestGenerationAsUtf8(generator, strength, 20);
                TestGenerationAsSecure(generator, strength, 20);
            }
            foreach (var strength in RandomStrengths)
            {
                TestGeneration(generator, Clause.RandomMappings[strength], 10);
                TestGenerationAsUtf8(generator, Clause.RandomMappings[strength], 10);
                TestGenerationAsSecure(generator, Clause.RandomMappings[strength], 10);
            }
        }
Beispiel #14
0
        private static void TestGithubIssue3(ReadablePassphraseGenerator generator)
        {
            // No trailing whitespace causes ArgumentOutOfRangeException in ConstantMutator
            // Caused with combination of numeric mutator at end of phrase, then constant mutator at end of phrase
            // https://github.com/ligos/readablepassphrasegenerator/issues/3
            var numericMutator = new NumericMutator()
            {
                When = NumericStyles.EndOfPhrase
            };
            var constantMutator = new ConstantMutator()
            {
                When = ConstantStyles.EndOfPhrase
            };
            var mutatorArray = new IMutator[] { numericMutator, constantMutator };
            var phrase       = generator.Generate(wordDelimiter: "__", mutators: mutatorArray);

            Console.WriteLine(phrase);
            if (!phrase.EndsWith(constantMutator.ValueToAdd))
            {
                throw new Exception("Should not be any trailing whitespace; final character should be the '.' from ConstantMutator");
            }

            phrase = generator.Generate(wordDelimiter: "", mutators: mutatorArray);
            Console.WriteLine(phrase);
            if (!phrase.EndsWith(constantMutator.ValueToAdd))
            {
                throw new Exception("Should not be any trailing whitespace; final character should be the '.' from ConstantMutator");
            }

            var sb = new StringBuilder("some passphrase without trailing whitespace");

            numericMutator.Mutate(sb, GetRandomness());
            constantMutator.Mutate(sb, GetRandomness());
            Console.WriteLine(sb.ToString());

            sb = new StringBuilder("some passphrase with extra trailing whitespace   ");
            numericMutator.Mutate(sb, GetRandomness());
            constantMutator.Mutate(sb, GetRandomness());
            Console.WriteLine(sb.ToString());
        }
 private static void TestBitbucketIssue16(ReadablePassphraseGenerator generator)
 {
     // Testing Bitbucket Issue #16 - always generating the definite article.
     GenerateCustomSamples(new Clause[]
     {
         //Noun = {
         //    Adjective->0, NoAdjective->1,
         //    NoArticle->100, DefiniteArticle->1, IndefiniteArticle->0, Demonstrative->0, PersonalPronoun->0,
         //    ProperNoun->0, CommonNoun->12, AdjectiveNoun->2,
         //    Number->0, NoNumber->1,
         //    Plural->0, Single->1,
         //    Preposition->0, NoPreposition->1,
         // }
         new NounClause()
         {
             CommonNounFactor    = 12, ProperNounFactor = 0, NounFromAdjectiveFactor = 2,
             SingularityFactor   = 1, PluralityFactor = 0,
             NoArticleFactor     = 100, DefiniteArticleFactor = 1, IndefiniteArticleFactor = 0, DemonstractiveFactor = 0, PersonalPronounFactor = 0,
             NoNumberFactor      = 1, NumberFactor = 0,
             NoAdjectiveFactor   = 1, AdjectiveFactor = 0,
             NoPrepositionFactor = 0, PrepositionFactor = 1
         },
     }
                           , generator, 10);
     // Try with no definite article - much better!
     // Singular requires an noun prelude, so it ignores the NoArticleFactor.
     GenerateCustomSamples(new Clause[]
     {
         new NounClause()
         {
             CommonNounFactor    = 12, ProperNounFactor = 0, NounFromAdjectiveFactor = 2,
             SingularityFactor   = 1, PluralityFactor = 0,
             NoArticleFactor     = 1, DefiniteArticleFactor = 0, IndefiniteArticleFactor = 0, DemonstractiveFactor = 0, PersonalPronounFactor = 0,
             NoNumberFactor      = 1, NumberFactor = 0,
             NoAdjectiveFactor   = 1, AdjectiveFactor = 0,
             NoPrepositionFactor = 0, PrepositionFactor = 1
         },
     }
                           , generator, 10);
 }
 private static void TestBitbucketIssue15(ReadablePassphraseGenerator generator)
 {
     // Testing Bitbucket Issue #15 - causes crash.
     GenerateCustomSamples(new Clause[]
     {
         // Adjective->1, NoAdjective->1,
         // NoArticle->50, DefiniteArticle->25, IndefiniteArticle->0, Demonstrative->1, PersonalPronoun->0,
         // ProperNoun->1, CommonNoun->5, AdjectiveNoun->0,
         // Number->0, NoNumber->1,
         // Plural->1, Single->1,
         // Preposition->1, NoPreposition->1
         new NounClause()
         {
             CommonNounFactor    = 5, ProperNounFactor = 1, NounFromAdjectiveFactor = 0,
             SingularityFactor   = 1, PluralityFactor = 1,
             NoArticleFactor     = 50, DefiniteArticleFactor = 25, IndefiniteArticleFactor = 0, DemonstractiveFactor = 1, PersonalPronounFactor = 0,
             NoNumberFactor      = 1, NumberFactor = 0,
             NoAdjectiveFactor   = 1, AdjectiveFactor = 1,
             NoPrepositionFactor = 1, PrepositionFactor = 1
         },
     }
                           , generator, 10);
 }
Beispiel #17
0
        static void RunMain()
        {
            // Generate and print phrases.
            if (!quiet)
            {
                var ver = GetProgramVersion();
                var idx = ver.IndexOf('.', ver.IndexOf('.', ver.IndexOf('.') + 1) + 1);
                Console.WriteLine("Readable Passphrase Generator {0}", ver.Substring(0, idx));
            }
            if (!quiet && anyLength > 0)
            {
                Console.WriteLine("Generating {0:N0} non-grammatic phrase(s) of length '{1}'...", count, anyLength);
            }
            else if (!quiet && String.IsNullOrEmpty(customPhrasePath))
            {
                Console.WriteLine("Generating {0:N0} phrase(s) of strength '{1}'...", count, strength);
            }
            else if (!quiet && !String.IsNullOrEmpty(customPhrasePath))
            {
                Console.WriteLine("Generating {0:N0} phrase(s) based on phrase description in '{1}'...", count, System.IO.Path.GetFileName(customPhrasePath));
            }
            if (!quiet && (maxLength < Int32.MaxValue || minLength > 1))
            {
                Console.WriteLine("Must be between {0:N0} and {1} characters.", minLength, maxLength == Int32.MaxValue ? "∞" : maxLength.ToString("N0"));
            }

            var generator = new ReadablePassphraseGenerator();

            // Must load dictionary before trying to generate.
            var dictSw  = System.Diagnostics.Stopwatch.StartNew();
            var loaderT = GetDictionaryLoaderType();

            // If the internal dictionary loader is being used and no other arguments are specified, tell it to use the default dictionary.
            if (loaderT == typeof(ExplicitXmlDictionaryLoader) && String.IsNullOrEmpty(loaderArguments.Trim()))
            {
                loaderArguments = "useDefaultDictionary=true";
            }

            // And load our dictionary!
            using (var loader = Activator.CreateInstance(loaderT) as IDictionaryLoader)
            {
                if (loader == null)
                {
                    throw new Exception($"Unable to create instance of dictionary loader {loaderT.FullName}");
                }
                generator.LoadDictionary(loader, loaderArguments);
            }
            dictSw.Stop();

            // Summarise actions and combinations / entropy.
            if (!quiet)
            {
                Console.WriteLine("Dictionary contains {0:N0} words (loaded in {1:N2}ms)", generator.Dictionary.Count, dictSw.Elapsed.TotalMilliseconds);
                PhraseCombinations combinations;
                if (anyLength > 0)
                {
                    combinations = generator.CalculateCombinations(NonGrammaticalClause(anyLength));
                }
                else if (strength != PhraseStrength.Custom)
                {
                    combinations = generator.CalculateCombinations(strength);
                }
                else
                {
                    combinations = generator.CalculateCombinations(phraseDescription);
                }
                Console.WriteLine("Average combinations ~{0:E3} (~{1:N2} bits)", combinations.OptionalAverage, combinations.OptionalAverageAsEntropyBits);
                Console.WriteLine("Total combinations {0:E3} - {1:E3} ({2:N2} - {3:N2} bits)", combinations.Shortest, combinations.Longest, combinations.ShortestAsEntropyBits, combinations.LongestAsEntropyBits);

                var upperTypeText = upperStyle == AllUppercaseStyles.RunOfLetters ? " run"
                                  : upperStyle == AllUppercaseStyles.WholeWord ? " word"
                                  : "";
                var upperTypeText2 = upperStyle == AllUppercaseStyles.RunOfLetters ? "run"
                                   : upperStyle == AllUppercaseStyles.WholeWord ? "word"
                                   : "capital";
                if (applyStandardMutators)
                {
                    Console.WriteLine("Using standard mutators (2 numbers, 2 capitals, period at end)");
                }
                else if (applyAlternativeMutators)
                {
                    Console.WriteLine("Using alternate mutators (2 numbers, 1 whole capital word, period at end)");
                }
                else if (numericStyle != 0 && upperStyle != 0 && constantStyle != 0)
                {
                    Console.WriteLine($"Using upper case{upperTypeText}, numeric and constant mutators ({upperCount:N0} {upperTypeText2}(s), {numericCount:N0} number(s))");
                }
                else if (numericStyle != 0 && upperStyle != 0 && constantStyle == 0)
                {
                    Console.WriteLine($"Using upper case{upperTypeText} and numeric mutators ({upperCount:N0} {upperTypeText2}(s), {numericCount:N0} number(s))");
                }
                else if (numericStyle == 0 && upperStyle != 0 && constantStyle != 0)
                {
                    Console.WriteLine($"Using upper case{upperTypeText} and constant mutators ({upperCount:N0} {upperTypeText2}(s))");
                }
                else if (numericStyle == 0 && upperStyle != 0 && constantStyle == 0)
                {
                    Console.WriteLine($"Using upper case{upperTypeText} mutator only ({upperCount:N0} {upperTypeText2}(s))");
                }
                else if (numericStyle != 0 && upperStyle == 0 && constantStyle != 0)
                {
                    Console.WriteLine($"Using numeric and constant mutators ({numericCount:N0} number(s))");
                }
                else if (numericStyle != 0 && upperStyle == 0 && constantStyle == 0)
                {
                    Console.WriteLine($"Using numeric mutator only ({numericCount:N0} number(s))");
                }
                else if (numericStyle == 0 && upperStyle == 0 && constantStyle != 0)
                {
                    Console.WriteLine($"Using constant mutator only");
                }
                else
                {
                    Console.WriteLine("Using no mutators");
                }
                Console.WriteLine();
            }

            // Generate!
            var genSw       = System.Diagnostics.Stopwatch.StartNew();
            int generated   = 0;
            int attempts    = 0;
            int maxAttempts = count * MaxAttemptsPerCount;
            var mutators    = applyStandardMutators ? new IMutator[] { UppercaseMutator.Basic, NumericMutator.Basic, ConstantMutator.Basic }
                         : applyAlternativeMutators ? new IMutator[] { UppercaseWordMutator.Basic, NumericMutator.Basic, ConstantMutator.Basic }
                         : Enumerable.Empty <IMutator>();

            if (upperStyle > 0 && upperStyle <= AllUppercaseStyles.Anywhere)
            {
                mutators = mutators.Concat(new IMutator[] { new UppercaseMutator()
                                                            {
                                                                When = (UppercaseStyles)upperStyle, NumberOfCharactersToCapitalise = upperCount
                                                            } });
            }
            if (upperStyle == AllUppercaseStyles.RunOfLetters)
            {
                mutators = mutators.Concat(new IMutator[] { new UppercaseRunMutator()
                                                            {
                                                                NumberOfRuns = upperCount
                                                            } });
            }
            if (upperStyle == AllUppercaseStyles.WholeWord)
            {
                mutators = mutators.Concat(new IMutator[] { new UppercaseWordMutator()
                                                            {
                                                                NumberOfWordsToCapitalise = upperCount
                                                            } });
            }
            if (numericStyle != 0)
            {
                mutators = mutators.Concat(new IMutator[] { new NumericMutator()
                                                            {
                                                                When = numericStyle, NumberOfNumbersToAdd = numericCount
                                                            } });
            }
            if (constantStyle != 0)
            {
                mutators = mutators.Concat(new IMutator[] { new ConstantMutator()
                                                            {
                                                                When = constantStyle, ValueToAdd = constantValue
                                                            } });
            }
            while (generated < count)
            {
                // Generate phrase.
                // We always include spaces in the phrase because the mutators rely on whitespace.
                string phrase;
                attempts++;
                if (anyLength > 0)
                {
                    phrase = generator.Generate(NonGrammaticalClause(anyLength), " ", mutators);
                }
                else if (strength == PhraseStrength.Custom)
                {
                    phrase = generator.Generate(phraseDescription, " ", mutators);
                }
                else
                {
                    phrase = generator.Generate(strength, " ", mutators);
                }

                // After mutators are applied, it's safe to remove white space.
                if (wordSeparator != " ")
                {
                    phrase = phrase.Replace(" ", wordSeparator);
                }

                // Clamp the length.
                if (phrase.Length >= minLength && phrase.Length <= maxLength)
                {
                    Console.WriteLine(phrase);
                    generated++;
                }
                if (attempts >= maxAttempts)
                {
                    break;
                }
            }
            genSw.Stop();

            // Summarise result.
            if (!quiet)
            {
                Console.WriteLine();
                Console.WriteLine("Generated {0:N0} phrase(s) in {1:N2}ms.", generated, genSw.Elapsed.TotalMilliseconds);
                if (attempts >= maxAttempts)
                {
                    Console.WriteLine("But unable to generate requested {0:N0} phrase(s) after {1:N0} attempts." + Environment.NewLine + "Perhaps try changing the minimum or maximum phrase length.", count, attempts);
                }
            }
        }
        private static void WriteStatisticsFor(ReadablePassphraseGenerator generator, PhraseStrength strength, int count, string filename)
        {
            Console.Write("Writing statistics to '{0}'...", filename);

            var wordHistogram           = new Dictionary <int, int>();
            var charHistogram           = new Dictionary <int, int>();
            var keepassQualityHistogram = new Dictionary <uint, int>();
            var combinations            = generator.CalculateCombinations(strength);

            for (int i = 0; i < count; i++)
            {
                var phrase = generator.Generate(strength);

                if (!charHistogram.ContainsKey(phrase.Length))
                {
                    charHistogram.Add(phrase.Length, 0);
                }
                charHistogram[phrase.Length] = charHistogram[phrase.Length] + 1;

                var wordCount = phrase.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries).Length;
                if (!wordHistogram.ContainsKey(wordCount))
                {
                    wordHistogram.Add(wordCount, 0);
                }
                wordHistogram[wordCount] = wordHistogram[wordCount] + 1;

                var keePassQualityEst = KeePassLib.Cryptography.QualityEstimation.EstimatePasswordBits(phrase.ToCharArray());
                if (!keepassQualityHistogram.ContainsKey(keePassQualityEst))
                {
                    keepassQualityHistogram.Add(keePassQualityEst, 0);
                }
                keepassQualityHistogram[keePassQualityEst] = keepassQualityHistogram[keePassQualityEst] + 1;
            }

            using (var writer = new System.IO.StreamWriter(filename, false, Encoding.UTF8))
            {
                writer.WriteLine("Word histogram");
                for (int i = wordHistogram.Keys.Min(); i < wordHistogram.Keys.Max() + 1; i++)
                {
                    writer.WriteLine("{0},{1}", i, wordHistogram.ContainsKey(i) ? wordHistogram[i] : 0);
                }
                writer.WriteLine();

                writer.WriteLine("Character histogram");
                for (int i = charHistogram.Keys.Min(); i < charHistogram.Keys.Max() + 1; i++)
                {
                    writer.WriteLine("{0},{1}", i, charHistogram.ContainsKey(i) ? charHistogram[i] : 0);
                }
                writer.WriteLine();

                writer.WriteLine("KeePass Quality Estimate");
                for (uint i = keepassQualityHistogram.Keys.Min(); i < keepassQualityHistogram.Keys.Max() + 1; i++)
                {
                    writer.WriteLine("{0},{1}", i, keepassQualityHistogram.ContainsKey(i) ? keepassQualityHistogram[i] : 0);
                }
                writer.WriteLine();

                writer.WriteLine("Combination counts");
                writer.WriteLine("Min:,{0:E3},{1:N2}", combinations.Shortest, combinations.ShortestAsEntropyBits);
                writer.WriteLine("Max:,{0:E3},{1:N2}", combinations.Longest, combinations.LongestAsEntropyBits);
                writer.WriteLine("Avg:,{0:E3},{1:N2}", combinations.OptionalAverage, combinations.OptionalAverageAsEntropyBits);

                writer.WriteLine();
                writer.WriteLine("Samples:");
                for (int i = 0; i < 20; i++)
                {
                    writer.WriteLine(generator.Generate(strength));
                }
            }

            Console.WriteLine(" Done.");

            bool isFirst = !System.IO.File.Exists(AllStatsCharFilename);

            using (var writer = new System.IO.StreamWriter(AllStatsCharFilename, true, Encoding.UTF8))
            {
                if (isFirst)
                {
                    writer.WriteLine("Strength,Min,Max,Avg,Median,Samples");
                }
                writer.WriteLine("{0},{1},{2},{3},{4},{5}", strength.ToString(), charHistogram.Keys.Min(), charHistogram.Keys.Max(), GetAvg(charHistogram), GetMedian(charHistogram), count);
            }
        }
 private static void GenerateSamples(PhraseStrength strength, ReadablePassphraseGenerator generator)
 {
     GenerateSamples(strength, generator, 20);
 }
        private static void GenerateCustomSamples(IEnumerable <MurrayGrant.ReadablePassphrase.PhraseDescription.Clause> clause, ReadablePassphraseGenerator generator, int count)
        {
            Console.WriteLine();
            Console.WriteLine("Custom samples:");
            var combinations = generator.CalculateCombinations(clause);

            Console.WriteLine("Combinations: {0:E3} ({1:N2} bits)", combinations.ToString(), combinations.EntropyBitsToString());
            for (int i = 0; i < count; i++)
            {
                Console.WriteLine(generator.Generate(clause));
            }
        }
        static void Main(string[] args)
        {
            Console.OutputEncoding = Encoding.UTF8;
            var sw        = System.Diagnostics.Stopwatch.StartNew();
            var generator = new ReadablePassphraseGenerator(GetRandomness());
            var loader    = new ExplicitXmlDictionaryLoader();
            var dict      = loader.LoadFrom(new DirectoryInfo(Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location)));

            generator.SetDictionary(dict);
            sw.Stop();
            Console.WriteLine("Loaded dictionary of type '{0}' with {1:N0} words in {2:N2}ms ({3:N3} words / sec)", loader.GetType().Name, generator.Dictionary.Count, sw.Elapsed.TotalMilliseconds, generator.Dictionary.Count / sw.Elapsed.TotalSeconds);

            // Basic statistics / samples.
            //GenerateSamples(PhraseStrength.Random, generator);
            //DictionaryCheck(generator);
            //CombinationCount(generator);

            // Short benchmarks.
            //BenchmarkGeneration(generator, PhraseStrength.Normal, 1000);
            //BenchmarkSecureGeneration(generator, PhraseStrength.Normal, 1000);
            //BenchmarkUtf8Generation(generator, PhraseStrength.Normal, 1000);
            //BenchmarkGeneration(generator, PhraseStrength.Strong, 1000);
            //BenchmarkGeneration(generator, PhraseStrength.Insane, 1000);
            //BenchmarkGeneration(generator, PhraseStrength.Random, 1000);

            // Test all combinations of phrase combinations / textual parsing.
            //TestAllStrengthsAndOutputs(generator);

            // Test spaces, no spaces and custom delimiter.
            //GenerateDelimiterSamples(PhraseStrength.Random, generator, 5, " ");
            //GenerateDelimiterSamples(PhraseStrength.Random, generator, 5, "");
            //GenerateDelimiterSamples(PhraseStrength.Random, generator, 5, ".");
            //GenerateDelimiterSamples(PhraseStrength.Random, generator, 5, "✶");

            // Generate statistics.
            //WriteAllStatistics(generator);

            // This is used to tinker with custom clauses, probabilities, grammar, etc.
            //TinkerWithCustomClause(generator);

            // Other test cases.
            //TestBitbucketIssue15(generator);
            //TestBitbucketIssue16(generator);

            // Longer benchmarks.
            //BenchmarkGeneration(generator, PhraseStrength.Normal, 10000);
            //BenchmarkGeneration(generator, PhraseStrength.Strong, 10000);
            //BenchmarkGeneration(generator, PhraseStrength.Insane, 10000);

            // Random function distribution tests.
            //TestCoinFlip(SeededRandom());
            //TestWeightedCoinFlip(SeededRandom(), 1, 1);
            //TestNextInt32(SeededRandom(), 4);
            //TestNextInt32(SeededRandom(), 15);
            //TestNextInt32(SeededRandom(), 50);
            //TestNextInt32(SeededRandom(), 64);
            //TestNextInt32(SeededRandom(), 256);
            //TestNextInt32(SeededRandom(), 1296);

            // TODO: Test load an alternate dictionary loader.

            // Test the config form.
#if NETFRAMEWORK        // No WinForms in NetCore
            //TestConfigForm(generator);
#endif
            // Test mutators.
            //GenerateMutatedSamples(PhraseStrength.Random, generator, 10, new IMutator[] { new UppercaseRunMutator() });
            //GenerateMutatedSamples(PhraseStrength.Random, generator, 10, new IMutator[] { new NumericMutator() });
            //GenerateMutatedSamples(PhraseStrength.Random, generator, 10, new IMutator[] { new ConstantMutator() });

            // Test loading the default dictionary.
            //var defaultDictSw = System.Diagnostics.Stopwatch.StartNew();
            //var defaultDict = MurrayGrant.ReadablePassphrase.Dictionaries.Default.Load();
            //defaultDictSw.Stop();
            //Console.WriteLine("Loaded default dictionary from assembly resource with {0:N0} words in {1:N2}ms ({2:N3} words / sec)", defaultDict.Count, defaultDictSw.Elapsed.TotalMilliseconds, defaultDict.Count / defaultDictSw.Elapsed.TotalSeconds);

            //var easyCreatedGenerator = MurrayGrant.ReadablePassphrase.Generator.Create();
            //Console.WriteLine("Loaded generator from Generator.Create() with default dictionary of {0:N0} words.", easyCreatedGenerator.Dictionary.Count);
        }