@@ -18,6 +18,13 @@ import QuantumArithmetic.WindowedArithmeticUtils.Util.ForceMeasureResetBigInt;
1818import QuantumArithmetic .WindowedArithmeticUtils .Util .BitLength ;
1919import QuantumArithmetic .WindowedArithmeticUtils .Xor .XorEqualConst ;
2020import QuantumArithmetic .WindowedArithmeticUtils .MulAdd_Window .PlusEqualConstTimesLEWindowed ;
21+ import QuantumArithmetic .Utils ;
22+ import Std .Arrays ;
23+ import Std .Convert ;
24+ import Std .Math ;
25+ import Std .TableLookup .* ;
26+ import Std .Arithmetic .RippleCarryCGIncByLE ;
27+ import QuantumArithmetic .LYY2021 .ModAdd ;
2128
2229operation Multiply (nx : Int , ny : Int , result_t : BigInt ,
2330 classical_factor_x : BigInt , quantum_factor_y : BigInt ) : BigInt {
@@ -52,4 +59,108 @@ operation MultiplyWindow (nx : Int, ny : Int, result_t : BigInt,
5259 return result ;
5360}
5461
55- export Multiply , MultiplyWindow ;
62+ internal function Skip2Data (
63+ generator : BigInt , period : BigInt , num_exponents : Int , num_bits : Int
64+ ) : Bool [][] {
65+ mutable total = 1L ;
66+ let num_entries = 1 <<< num_exponents ;
67+ mutable table = [[false , size = num_bits ], size = num_entries ];
68+
69+ for k2 in 0 .. num_entries - 1 {
70+ // Convert total to bits (little-endian)
71+ set table w/= k2 <- Convert .BigIntAsBoolArray (total , num_bits );
72+ set total *= generator ;
73+ set total %= period ;
74+ }
75+
76+ return table ;
77+ }
78+
79+ /// Computes ans=(base^exponent)%modulus.
80+ /// ans must be prepared in zero state.
81+ /// base must be coprime with modulus.
82+ /// Doesn't change exponent.
83+ /// Fig. 7 in the paper
84+ operation ModExpWindow (exponent : Qubit [], ans : Qubit [], base : BigInt , modulus : BigInt ,
85+ expWindowLen : Int , mulWindowLen : Int
86+ ) : Unit is Adj + Ctl {
87+ let n1 = Length (exponent );
88+ let n2 = Length (ans );
89+
90+ let expWindows = Arrays .Chunks (expWindowLen , exponent );
91+
92+ // skip the first two expWindows with a direct lookup
93+ // based on [Gidney 2025](https://arxiv.org/abs/2505.15917)
94+ let skipNum =
95+ if (expWindowLen * 2 < n1 ) {
96+ expWindowLen * 2
97+ } else {
98+ n1
99+ };
100+ let data = Skip2Data (base , modulus , skipNum , n2 );
101+ use output = Qubit [n2 ];
102+ within {
103+ Select (data , expWindows [0 ] + expWindows [1 ], output );
104+ } apply {
105+ Utils .ParallelCNOT (output , ans );
106+ }
107+
108+ for i in 2 .. Length (expWindows )- 1 {
109+ let adjustedBase = Math .ExpModL (base , 1L <<< (i * expWindowLen ), modulus );
110+ if (i % 2 == 1 ) {
111+ AddExpModWindowed (adjustedBase , modulus , 1 , mulWindowLen , expWindows [i ], output , ans );
112+ AddExpModWindowed (Math .InverseModL (adjustedBase , modulus ), modulus , - 1 , mulWindowLen , expWindows [i ], ans , output );
113+ } else {
114+ AddExpModWindowed (adjustedBase , modulus , 1 , mulWindowLen , expWindows [i ], ans , output );
115+ AddExpModWindowed (Math .InverseModL (adjustedBase , modulus ), modulus , - 1 , mulWindowLen , expWindows [i ], output , ans );
116+ }
117+ }
118+ if (Length (expWindows ) % 2 == 1 ) {
119+ // Handle the case where there are more than 2 exponent windows
120+ Utils .ParallelSWAP (ans , output );
121+ }
122+ }
123+
124+ internal function ModExpData (factor : BigInt , expLength : Int , mulLength : Int , base : BigInt , mod : BigInt , sign : Int , numBits : Int ) : Bool [][] {
125+ mutable data = [[false , size = numBits ], size = 2 ^ (expLength + mulLength )];
126+ for b in 0 .. 2 ^ mulLength - 1 {
127+ for a in 0 .. 2 ^ expLength - 1 {
128+ let idx = b * 2 ^ expLength + a ;
129+ let value = Math .ModulusL (factor * Convert .IntAsBigInt (b ) * Convert .IntAsBigInt (sign ) * (base ^ a ), mod );
130+ set data w/= idx <- Convert .BigIntAsBoolArray (value , numBits );
131+ }
132+ }
133+
134+ data
135+ }
136+
137+ /// Computes zs += ys * (base ^ xs) % mod (for small registers xs and ys)
138+ /// based on Fig. 5 in [Gidney 2019](https://arxiv.org/abs/1905.07682)
139+ internal operation AddExpModWindowed (
140+ base : BigInt ,
141+ mod : BigInt ,
142+ sign : Int ,
143+ mulWindowLen : Int ,
144+ xs : Qubit [],
145+ ys : Qubit [],
146+ zs : Qubit []
147+ ) : Unit is Adj + Ctl {
148+ // split factor into parts
149+ let factorWindows = Arrays .Chunks (mulWindowLen , ys );
150+
151+ for i in 0 .. Length (factorWindows )- 1 {
152+ // compute data for table lookup
153+ let factorValue = Math .ExpModL (2L , Convert .IntAsBigInt (i * mulWindowLen ), mod );
154+ let data = ModExpData (factorValue , Length (xs ), Length (factorWindows [i ]), base , mod , sign , Length (zs ));
155+
156+ use output = Qubit [Length (data [0 ])];
157+
158+ within {
159+ Select (data , xs + factorWindows [i ], output );
160+ } apply {
161+ ModAdd (output , zs , mod );
162+ }
163+ }
164+ }
165+
166+ export Multiply , MultiplyWindow , ModExpWindow ;
0 commit comments