Gost3410ParametersGenerator
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using System;
namespace Org.BouncyCastle.Crypto.Generators
{
    public class Gost3410ParametersGenerator
    {
        private int size;
        private int typeproc;
        private SecureRandom init_random;
        public void Init(int size, int typeProcedure, SecureRandom random)
        {
            this.size = size;
            typeproc = typeProcedure;
            init_random = random;
        }
        private int procedure_A(int x0, int c, BigInteger[] pq, int size)
        {
            while (x0 < 0 || x0 > 65536) {
                x0 = init_random.NextInt() / 32768;
            }
            while (c < 0 || c > 65536 || c / 2 == 0) {
                c = init_random.NextInt() / 32768 + 1;
            }
            BigInteger value = BigInteger.ValueOf(c);
            BigInteger val = BigInteger.ValueOf(19381);
            BigInteger[] array = new BigInteger[1] {
                BigInteger.ValueOf(x0)
            };
            int[] array2 = new int[1] {
                size
            };
            int num = 0;
            for (int i = 0; array2[i] >= 17; i++) {
                int[] array3 = new int[array2.Length + 1];
                Array.Copy(array2, 0, array3, 0, array2.Length);
                array2 = new int[array3.Length];
                Array.Copy(array3, 0, array2, 0, array3.Length);
                array2[i + 1] = array2[i] / 2;
                num = i + 1;
            }
            BigInteger[] array4 = new BigInteger[num + 1];
            array4[num] = new BigInteger("8003", 16);
            int num2 = num - 1;
            for (int j = 0; j < num; j++) {
                int num3 = array2[num2] / 16;
                while (true) {
                    BigInteger[] array5 = new BigInteger[array.Length];
                    Array.Copy(array, 0, array5, 0, array.Length);
                    array = new BigInteger[num3 + 1];
                    Array.Copy(array5, 0, array, 0, array5.Length);
                    for (int k = 0; k < num3; k++) {
                        array[k + 1] = array[k].Multiply(val).Add(value).Mod(BigInteger.Two.Pow(16));
                    }
                    BigInteger bigInteger = BigInteger.Zero;
                    for (int l = 0; l < num3; l++) {
                        bigInteger = bigInteger.Add(array[l].ShiftLeft(16 * l));
                    }
                    array[0] = array[num3];
                    BigInteger bigInteger2 = BigInteger.One.ShiftLeft(array2[num2] - 1).Divide(array4[num2 + 1]).Add(bigInteger.ShiftLeft(array2[num2] - 1).Divide(array4[num2 + 1].ShiftLeft(16 * num3)));
                    if (bigInteger2.TestBit(0))
                        bigInteger2 = bigInteger2.Add(BigInteger.One);
                    while (true) {
                        BigInteger bigInteger3 = bigInteger2.Multiply(array4[num2 + 1]);
                        if (bigInteger3.BitLength > array2[num2])
                            break;
                        array4[num2] = bigInteger3.Add(BigInteger.One);
                        if (BigInteger.Two.ModPow(bigInteger3, array4[num2]).CompareTo(BigInteger.One) == 0 && BigInteger.Two.ModPow(bigInteger2, array4[num2]).CompareTo(BigInteger.One) != 0)
                            goto end_IL_0103;
                        bigInteger2 = bigInteger2.Add(BigInteger.Two);
                    }
                    continue;
                    continue;
                    end_IL_0103:
                    break;
                }
                if (--num2 < 0) {
                    pq[0] = array4[0];
                    pq[1] = array4[1];
                    return array[0].IntValue;
                }
            }
            return array[0].IntValue;
        }
        private long procedure_Aa(long x0, long c, BigInteger[] pq, int size)
        {
            while (x0 < 0 || x0 > 4294967296) {
                x0 = init_random.NextInt() * 2;
            }
            while (c < 0 || c > 4294967296 || c / 2 == 0) {
                c = init_random.NextInt() * 2 + 1;
            }
            BigInteger value = BigInteger.ValueOf(c);
            BigInteger val = BigInteger.ValueOf(97781173);
            BigInteger[] array = new BigInteger[1] {
                BigInteger.ValueOf(x0)
            };
            int[] array2 = new int[1] {
                size
            };
            int num = 0;
            for (int i = 0; array2[i] >= 33; i++) {
                int[] array3 = new int[array2.Length + 1];
                Array.Copy(array2, 0, array3, 0, array2.Length);
                array2 = new int[array3.Length];
                Array.Copy(array3, 0, array2, 0, array3.Length);
                array2[i + 1] = array2[i] / 2;
                num = i + 1;
            }
            BigInteger[] array4 = new BigInteger[num + 1];
            array4[num] = new BigInteger("8000000B", 16);
            int num2 = num - 1;
            for (int j = 0; j < num; j++) {
                int num3 = array2[num2] / 32;
                while (true) {
                    BigInteger[] array5 = new BigInteger[array.Length];
                    Array.Copy(array, 0, array5, 0, array.Length);
                    array = new BigInteger[num3 + 1];
                    Array.Copy(array5, 0, array, 0, array5.Length);
                    for (int k = 0; k < num3; k++) {
                        array[k + 1] = array[k].Multiply(val).Add(value).Mod(BigInteger.Two.Pow(32));
                    }
                    BigInteger bigInteger = BigInteger.Zero;
                    for (int l = 0; l < num3; l++) {
                        bigInteger = bigInteger.Add(array[l].ShiftLeft(32 * l));
                    }
                    array[0] = array[num3];
                    BigInteger bigInteger2 = BigInteger.One.ShiftLeft(array2[num2] - 1).Divide(array4[num2 + 1]).Add(bigInteger.ShiftLeft(array2[num2] - 1).Divide(array4[num2 + 1].ShiftLeft(32 * num3)));
                    if (bigInteger2.TestBit(0))
                        bigInteger2 = bigInteger2.Add(BigInteger.One);
                    while (true) {
                        BigInteger bigInteger3 = bigInteger2.Multiply(array4[num2 + 1]);
                        if (bigInteger3.BitLength > array2[num2])
                            break;
                        array4[num2] = bigInteger3.Add(BigInteger.One);
                        if (BigInteger.Two.ModPow(bigInteger3, array4[num2]).CompareTo(BigInteger.One) == 0 && BigInteger.Two.ModPow(bigInteger2, array4[num2]).CompareTo(BigInteger.One) != 0)
                            goto end_IL_0108;
                        bigInteger2 = bigInteger2.Add(BigInteger.Two);
                    }
                    continue;
                    continue;
                    end_IL_0108:
                    break;
                }
                if (--num2 < 0) {
                    pq[0] = array4[0];
                    pq[1] = array4[1];
                    return array[0].LongValue;
                }
            }
            return array[0].LongValue;
        }
        private void procedure_B(int x0, int c, BigInteger[] pq)
        {
            while (x0 < 0 || x0 > 65536) {
                x0 = init_random.NextInt() / 32768;
            }
            while (c < 0 || c > 65536 || c / 2 == 0) {
                c = init_random.NextInt() / 32768 + 1;
            }
            BigInteger[] array = new BigInteger[2];
            BigInteger bigInteger = null;
            BigInteger bigInteger2 = null;
            BigInteger bigInteger3 = null;
            BigInteger value = BigInteger.ValueOf(c);
            BigInteger val = BigInteger.ValueOf(19381);
            x0 = procedure_A(x0, c, array, 256);
            bigInteger = array[0];
            x0 = procedure_A(x0, c, array, 512);
            bigInteger2 = array[0];
            BigInteger[] array2 = new BigInteger[65] {
                BigInteger.ValueOf(x0),
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null
            };
            BigInteger bigInteger4 = bigInteger.Multiply(bigInteger2);
            while (true) {
                for (int i = 0; i < 64; i++) {
                    array2[i + 1] = array2[i].Multiply(val).Add(value).Mod(BigInteger.Two.Pow(16));
                }
                BigInteger bigInteger5 = BigInteger.Zero;
                for (int j = 0; j < 64; j++) {
                    bigInteger5 = bigInteger5.Add(array2[j].ShiftLeft(16 * j));
                }
                array2[0] = array2[64];
                BigInteger bigInteger6 = BigInteger.One.ShiftLeft(1023).Divide(bigInteger4).Add(bigInteger5.ShiftLeft(1023).Divide(bigInteger4.ShiftLeft(1024)));
                if (bigInteger6.TestBit(0))
                    bigInteger6 = bigInteger6.Add(BigInteger.One);
                while (true) {
                    BigInteger bigInteger7 = bigInteger4.Multiply(bigInteger6);
                    if (bigInteger7.BitLength > 1024)
                        break;
                    bigInteger3 = bigInteger7.Add(BigInteger.One);
                    if (BigInteger.Two.ModPow(bigInteger7, bigInteger3).CompareTo(BigInteger.One) == 0 && BigInteger.Two.ModPow(bigInteger.Multiply(bigInteger6), bigInteger3).CompareTo(BigInteger.One) != 0) {
                        pq[0] = bigInteger3;
                        pq[1] = bigInteger;
                        return;
                    }
                    bigInteger6 = bigInteger6.Add(BigInteger.Two);
                }
            }
        }
        private void procedure_Bb(long x0, long c, BigInteger[] pq)
        {
            while (x0 < 0 || x0 > 4294967296) {
                x0 = init_random.NextInt() * 2;
            }
            while (c < 0 || c > 4294967296 || c / 2 == 0) {
                c = init_random.NextInt() * 2 + 1;
            }
            BigInteger[] array = new BigInteger[2];
            BigInteger bigInteger = null;
            BigInteger bigInteger2 = null;
            BigInteger bigInteger3 = null;
            BigInteger value = BigInteger.ValueOf(c);
            BigInteger val = BigInteger.ValueOf(97781173);
            x0 = procedure_Aa(x0, c, array, 256);
            bigInteger = array[0];
            x0 = procedure_Aa(x0, c, array, 512);
            bigInteger2 = array[0];
            BigInteger[] array2 = new BigInteger[33] {
                BigInteger.ValueOf(x0),
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null
            };
            BigInteger bigInteger4 = bigInteger.Multiply(bigInteger2);
            while (true) {
                for (int i = 0; i < 32; i++) {
                    array2[i + 1] = array2[i].Multiply(val).Add(value).Mod(BigInteger.Two.Pow(32));
                }
                BigInteger bigInteger5 = BigInteger.Zero;
                for (int j = 0; j < 32; j++) {
                    bigInteger5 = bigInteger5.Add(array2[j].ShiftLeft(32 * j));
                }
                array2[0] = array2[32];
                BigInteger bigInteger6 = BigInteger.One.ShiftLeft(1023).Divide(bigInteger4).Add(bigInteger5.ShiftLeft(1023).Divide(bigInteger4.ShiftLeft(1024)));
                if (bigInteger6.TestBit(0))
                    bigInteger6 = bigInteger6.Add(BigInteger.One);
                while (true) {
                    BigInteger bigInteger7 = bigInteger4.Multiply(bigInteger6);
                    if (bigInteger7.BitLength > 1024)
                        break;
                    bigInteger3 = bigInteger7.Add(BigInteger.One);
                    if (BigInteger.Two.ModPow(bigInteger7, bigInteger3).CompareTo(BigInteger.One) == 0 && BigInteger.Two.ModPow(bigInteger.Multiply(bigInteger6), bigInteger3).CompareTo(BigInteger.One) != 0) {
                        pq[0] = bigInteger3;
                        pq[1] = bigInteger;
                        return;
                    }
                    bigInteger6 = bigInteger6.Add(BigInteger.Two);
                }
            }
        }
        private BigInteger procedure_C(BigInteger p, BigInteger q)
        {
            BigInteger bigInteger = p.Subtract(BigInteger.One);
            BigInteger e = bigInteger.Divide(q);
            BigInteger bigInteger3;
            while (true) {
                BigInteger bigInteger2 = new BigInteger(p.BitLength, init_random);
                if (bigInteger2.CompareTo(BigInteger.One) > 0 && bigInteger2.CompareTo(bigInteger) < 0) {
                    bigInteger3 = bigInteger2.ModPow(e, p);
                    if (bigInteger3.CompareTo(BigInteger.One) != 0)
                        break;
                }
            }
            return bigInteger3;
        }
        public Gost3410Parameters GenerateParameters()
        {
            BigInteger[] array = new BigInteger[2];
            BigInteger bigInteger = null;
            BigInteger bigInteger2 = null;
            BigInteger bigInteger3 = null;
            if (typeproc == 1) {
                int x = init_random.NextInt();
                int c = init_random.NextInt();
                switch (size) {
                case 512:
                    procedure_A(x, c, array, 512);
                    break;
                case 1024:
                    procedure_B(x, c, array);
                    break;
                default:
                    throw new ArgumentException("Ooops! key size 512 or 1024 bit.");
                }
                bigInteger2 = array[0];
                bigInteger = array[1];
                bigInteger3 = procedure_C(bigInteger2, bigInteger);
                return new Gost3410Parameters(bigInteger2, bigInteger, bigInteger3, new Gost3410ValidationParameters(x, c));
            }
            long num = init_random.NextLong();
            long num2 = init_random.NextLong();
            switch (size) {
            case 512:
                procedure_Aa(num, num2, array, 512);
                break;
            case 1024:
                procedure_Bb(num, num2, array);
                break;
            default:
                throw new InvalidOperationException("Ooops! key size 512 or 1024 bit.");
            }
            bigInteger2 = array[0];
            bigInteger = array[1];
            bigInteger3 = procedure_C(bigInteger2, bigInteger);
            return new Gost3410Parameters(bigInteger2, bigInteger, bigInteger3, new Gost3410ValidationParameters(num, num2));
        }
    }
}