// register x - initially loaded with x
        // register N - initially loaded with N
        // control - control bit
        // other registers - initially 0
        // after computation register B changes and contains: [(a*x) mod N]
        // Insecure version: registers widths etc. are not checked
        public static void CMultModulo(
            this QuantumComputer comp,
            Register a,
            Register b,
            Register c,
            Register N,
            Register x,
            RegisterRef control,
            ulong valueA,
            ulong valueN)
        {
            ulong power2 = 1;
            for (int i = 0; i < x.Width; i++, power2 *= 2)
            {
                // loading A register with (2^i * a) mod N
                ulong toLoad = (valueA * power2) % valueN;
                comp.LoadNumber(a, toLoad, control, x[i]);

                // adding [(2^i * a) + B] modulo N
                comp.AddModulo(a, b, c, N, valueN);

                // unloading [(2^i * a) mod N] from A register
                comp.LoadNumber(a, toLoad, control, x[i]);
            }

            // if control == 0
            // then B register contains still 0
            // so we copy X register into B register
            comp.SigmaX(control);
            for (int i = 0; i < x.Width; i++)
            {
                comp.Toffoli(b[i], control, x[i]);
            }
            comp.SigmaX(control);
        }
        // register x - initially loaded with x
        // register N - initially loaded with N
        // control - control bit
        // other registers - initially 0
        // after computation register B changes and contains: [(a*x) mod N]
        // Insecure version: registers widths etc. are not checked
        public static void CMultModulo(
            this QuantumComputer comp,
            Register a,
            Register b,
            Register c,
            Register N,
            Register x,
            RegisterRef control,
            ulong valueA,
            ulong valueN)
        {
            if (comp.Group)
            {
                object[] parameters = new object[] { comp, a, b, c, N, x, control, valueA, valueN };
                comp.AddParametricGate("CMultModulo", parameters);
                return;
            }
            else
            {
                comp.Group = true;
            }

            ulong power2 = 1;
            for (int i = 0; i < x.Width; i++, power2 *= 2)
            {
                // loading A register with (2^i * a) mod N
                ulong toLoad = (valueA * power2) % valueN;
                comp.LoadNumber(a, toLoad, control, x[i]);

                // adding [(2^i * a) + B] modulo N
                comp.AddModulo(a, b, c, N, valueN);

                // unloading [(2^i * a) mod N] from A register
                comp.LoadNumber(a, toLoad, control, x[i]);
            }

            // if control == 0
            // then B register contains still 0
            // so we copy X register into B register
            comp.SigmaX(control);
            for (int i = 0; i < x.Width; i++)
            {
                comp.Toffoli(b[i], control, x[i]);
            }
            comp.SigmaX(control);
        }
        // register A - initially loaded with a
        // register B - initially loaded with b
        // after computation in register B: (a+b) mod N
        // using scratch registers inside
        // register B must be exactly one bit wider than A to store carry bit
        // Secure version: throws Exceptions if arguments are invalid
        public static void AddModulo(
            this QuantumComputer comp,
            Register a,
            Register b,
            ulong valueN)
        {
            Validate(a, b, valueN);

            Register c = comp.NewRegister(0, a.Width + 1);
            Register N = comp.NewRegister(valueN, a.Width);

            comp.AddModulo(a, b, c, N, valueN);

            comp.DeleteRegister(ref N);
            comp.DeleteRegister(ref c);
        }
        // register A - initially loaded with a
        // register B - initially loaded with b
        // after computation in register B: (a+b) mod N
        // using scratch registers inside
        // register B must be exactly one bit wider than A to store carry bit
        // Secure version: throws Exceptions if arguments are invalid
        public static void AddModulo(
            this QuantumComputer comp,
            Register a,
            Register b,
            ulong valueN)
        {
            if (comp.Group)
            {
                object[] parameters = new object[] { comp, a, b, valueN };
                comp.AddParametricGate("AddModulo", parameters);
                return;
            }
            else
            {
                comp.Group = true;
            }

            Validate(a, b, valueN);

            Register c = comp.NewRegister(0, a.Width + 1);
            Register N = comp.NewRegister(valueN, a.Width);

            comp.AddModulo(a, b, c, N, valueN);

            comp.DeleteRegister(ref N);
            comp.DeleteRegister(ref c);
        }