// register X - initially loaded with x // register X_1 - initially loaded with 1 // W = width(a) = width(N) // width(b) = width(c) = width(x1) = W + 1 // width(X) is 2 * W // register N - initially loaded with N // other registers - initially 0 // after computation register X_1 changes and contains: [(a^x) mod N] // Insecure version: registers widths etc. are not checked public static void ExpModulo( this QuantumComputer comp, Register a, Register b, Register c, Register N, Register x1, Register x, int valueA, int valueN) { if (comp.Group) { object[] parameters = new object[] { comp, a, b, c, N, x1, x, valueA, valueN }; comp.AddParametricGate("ExpModulo", parameters); return; } else { comp.Group = true; } bool firstRegisterB = false; int pow_a_2 = valueA; for (int i = 0; i < x.Width; i++) { // finding the inversion modulo of pow_a_2 int inv_mod = InversionModulo(pow_a_2, valueN); if (firstRegisterB) { comp.CMultModulo(a, x1, c, N, b, x[i], (ulong)pow_a_2, (ulong)valueN); comp.InverseCMultModulo(a, b, c, N, x1, x[i], (ulong)inv_mod, (ulong)valueN); } else { comp.CMultModulo(a, b, c, N, x1, x[i], (ulong)pow_a_2, (ulong)valueN); comp.InverseCMultModulo(a, x1, c, N, b, x[i], (ulong)inv_mod, (ulong)valueN); } pow_a_2 = (pow_a_2 * pow_a_2) % valueN; firstRegisterB = !firstRegisterB; } }
// register x - initially loaded with x // register b - initially loaded with 0 // after computation register b changes and contains: [(a*x) mod N] // Secure version: throws Exceptions if arguments are invalid public static void CMultModulo( this QuantumComputer comp, Register x, Register b, RegisterRef control, ulong valueA, ulong valueN) { Validate(x, b, valueN); Register a = comp.NewRegister(0, x.Width - 1); Register c = comp.NewRegister(0, x.Width); Register N = comp.NewRegister(valueN, x.Width - 1); comp.CMultModulo(a, b, c, N, x, control, valueA, valueN); comp.DeleteRegister(ref N); comp.DeleteRegister(ref c); comp.DeleteRegister(ref a); }
/// <summary> /// <para> /// Performs (a^x) modulo N, for given integers a and N. The x (one value or a superposition) /// is given in the input register x. /// </para> /// <para> /// After computation, the result (or results, when x stores superposition of multiple integers) is stored in /// register x1. /// </para> /// <para> /// This method is a variant of <c>ExpModulo</c> function, which operates directly on quantum registers given as arguments. /// It neither allocates nor frees any additional registers. It is thus recommended, when there is a need for performing /// modular exponentiation repeatedly. However, this variant has strict requirements for the width of each given register /// and if they are not fullfilled, the method gives unexpected results. /// </para> /// </summary> /// <remarks> /// <para> /// There are precise requirements for the width of each register given as argument. They result from a need for carry bits, /// overflow flag and a requirement for ensuring that the operation is inversible. /// </para> /// <para> /// Let <b>WIDTH</b> equals the number of bits required to store N. /// </para> /// <para> /// The width of x register must equal <b>2 * WIDTH</b>. This value results from the requirements of Peter Shor's /// algorithm. Such a width ensures that the probability of getting the right result will be enough high. /// </para> /// </remarks> /// <param name="comp">The QuantumComputer instance.</param> /// <param name="a">Accumulator register. Its initial value must be 0. Its width must equal <b>WIDTH</b> (See Remarks).</param> /// <param name="b">Helper register. Its initial value must be 0. Its width must equal <b>WIDTH + 1</b> (See Remarks).</param> /// <param name="c">Register for storing carry bits. Its initial value must be 0. Its width must equal <b>WIDTH + 1</b> (See Remarks).</param> /// <param name="N">Register for N. Its initial value must equal N. Its width must equal <b>WIDTH</b> (See Remarks).</param> /// <param name="x1">Output register. Its initial value must equal 1. Its width must equal <b>WIDTH + 1</b> (See Remarks).</param> /// <param name="x">Register for x. Its initial value could be any integer or a superposition of multiple integers. Its width must equal <b>2 * WIDTH</b> (See Remarks).</param> /// <param name="valueA">Integer value of a. (For computing (a^x) modulo N).</param> /// <param name="valueN">Integer value of N. (For computing (a^x) modulo N).</param> public static void ExpModulo( this QuantumComputer comp, Register a, Register b, Register c, Register N, Register x1, Register x, int valueA, int valueN) { bool firstRegisterB = false; int pow_a_2 = valueA; for (int i = 0; i < x.Width; i++) { // finding the inversion modulo of pow_a_2 int inv_mod = InversionModulo(pow_a_2, valueN); if (firstRegisterB) { comp.CMultModulo(a, x1, c, N, b, x[i], (ulong)pow_a_2, (ulong)valueN); comp.InverseCMultModulo(a, b, c, N, x1, x[i], (ulong)inv_mod, (ulong)valueN); } else { comp.CMultModulo(a, b, c, N, x1, x[i], (ulong)pow_a_2, (ulong)valueN); comp.InverseCMultModulo(a, x1, c, N, b, x[i], (ulong)inv_mod, (ulong)valueN); } pow_a_2 = (pow_a_2 * pow_a_2) % valueN; firstRegisterB = !firstRegisterB; } }
// register x - initially loaded with x // register b - initially loaded with 0 // after computation register b changes and contains: [(a*x) mod N] // Secure version: throws Exceptions if arguments are invalid public static void CMultModulo( this QuantumComputer comp, Register x, Register b, RegisterRef control, ulong valueA, ulong valueN) { if (comp.Group) { object[] parameters = new object[] { comp, x, b, control, valueA, valueN }; comp.AddParametricGate("CMultModulo", parameters); return; } else { comp.Group = true; } Validate(x, b, valueN); Register a = comp.NewRegister(0, x.Width - 1); Register c = comp.NewRegister(0, x.Width); Register N = comp.NewRegister(valueN, x.Width - 1); comp.CMultModulo(a, b, c, N, x, control, valueA, valueN); comp.DeleteRegister(ref N); comp.DeleteRegister(ref c); comp.DeleteRegister(ref a); }