internal static void Print(Formatter formatter, string groupName)
        {
            SGNames  sgNameEnum = GetSGName(groupName);
            SGParams sgp        = SubgroupRecommendedParameters.sgParams[(int)sgNameEnum];

            sgp.Oid = SubgroupRecommendedParameters.OID[(int)sgNameEnum];
            formatter.PrintText("OID", "UCHAR", null, sgp.Oid);
            formatter.PrintBigInteger("p", "UCHAR", null, sgp.p);
            formatter.PrintBigInteger("q", "UCHAR", null, sgp.q);
            formatter.PrintBigInteger("g", "UCHAR", null, sgp.g);
            formatter.PrintHex("domainParamSeed", "UCHAR", null, sgp.domain_parameter_seed);
            formatter.PrintBigInteger("e", "UCHAR", null, sgp.e);

            // g_1 ... g_n
            for (int i = 1; i <= NumberOfPregeneratedGenerators; i++)
            {
                formatter.PrintBigInteger("g" + i, "UCHAR", null, sgp.g_i[i - 1], sgp.counter[i - 1]);
            }

            // g_t
            formatter.PrintBigInteger("gt", "UCHAR", null, sgp.g_t, sgp.counter_t);

            // g_d
            formatter.PrintBigInteger("gd", "UCHAR", null, sgp.g_d, sgp.counter_d);
        }
        static public SGParams GenerateParameters(string groupName)
        {
            SGParams sgParams = new SGParams();

            SGNames  sgNameEnum = GetSGName(groupName);
            SGParams sgp        = SubgroupRecommendedParameters.sgParams[(int)sgNameEnum];

            sgParams.Oid = SubgroupRecommendedParameters.OID[(int)sgNameEnum];

            if (sgNameEnum == SGNames.L1024N160)
            {
                sgParams.p = new BigInteger(1, L1024N160.p);
                sgParams.q = new BigInteger(1, L1024N160.q);
                sgParams.domain_parameter_seed = L1024N160.domainParameterSeed;
            }
            else if (sgNameEnum == SGNames.L2048N256)
            {
                sgParams.p = new BigInteger(1, L2048N256.p);
                sgParams.q = new BigInteger(1, L2048N256.q);
                sgParams.domain_parameter_seed = L2048N256.domainParameterSeed;
            }
            else if (sgNameEnum == SGNames.L3072N256)
            {
                sgParams.p = new BigInteger(1, L3072N256.p);
                sgParams.q = new BigInteger(1, L3072N256.q);
                sgParams.domain_parameter_seed = L3072N256.domainParameterSeed;
            }
            else
            {
                throw new ArgumentException("unsupported group: " + sgNameEnum);
            }

            // g
            sgParams.g = FIPS_186_3_AnnexA_2_3(sgParams.p, sgParams.q, sgParams.domain_parameter_seed, 0, null, out sgParams.counter_g);

            // e = (p-1)/q (for verifiably random group generation)
            sgParams.e = sgParams.p.Subtract(BigInteger.One).Divide(sgParams.q);

            // g_1 ... g_n
            sgParams.g_i     = new BigInteger[NumberOfPregeneratedGenerators];
            sgParams.counter = new int[NumberOfPregeneratedGenerators];
            for (int i = 1; i <= NumberOfPregeneratedGenerators; i++)
            {
                sgParams.g_i[i - 1] = FIPS_186_3_AnnexA_2_3(sgParams.p, sgParams.q, sgParams.domain_parameter_seed, (byte)i, null, out sgParams.counter[i - 1]);
            }

            // g_t
            sgParams.g_t = FIPS_186_3_AnnexA_2_3(sgParams.p, sgParams.q, sgParams.domain_parameter_seed, 255, null, out sgParams.counter_t);

            // g_d
            sgParams.g_d = FIPS_186_3_AnnexA_2_3(sgParams.p, sgParams.q, sgParams.domain_parameter_seed, 254, null, out sgParams.counter_d);

            return(sgParams);
        }