• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.bouncycastle.math.ec;
2 
3 import java.math.BigInteger;
4 
5 public abstract class WNafUtil
6 {
7     private static int[] DEFAULT_WINDOW_SIZE_CUTOFFS = new int[]{ 13, 41, 121, 337, 897, 2305 };
8 
generateCompactNaf(BigInteger k)9     public static int[] generateCompactNaf(BigInteger k)
10     {
11         if ((k.bitLength() >>> 16) != 0)
12         {
13             throw new IllegalArgumentException("'k' must have bitlength < 2^16");
14         }
15 
16         BigInteger _3k = k.shiftLeft(1).add(k);
17 
18         int digits = _3k.bitLength() - 1;
19         int[] naf = new int[(digits + 1) >> 1];
20 
21         int length = 0, zeroes = 0;
22         for (int i = 1; i <= digits; ++i)
23         {
24             boolean _3kBit = _3k.testBit(i);
25             boolean kBit = k.testBit(i);
26 
27             if (_3kBit == kBit)
28             {
29                 ++zeroes;
30             }
31             else
32             {
33                 int digit  = kBit ? -1 : 1;
34                 naf[length++] = (digit << 16) | zeroes;
35                 zeroes = 0;
36             }
37         }
38 
39         if (naf.length > length)
40         {
41             naf = trim(naf, length);
42         }
43 
44         return naf;
45     }
46 
generateCompactWindowNaf(int width, BigInteger k)47     public static int[] generateCompactWindowNaf(int width, BigInteger k)
48     {
49         if (width == 2)
50         {
51             return generateCompactNaf(k);
52         }
53 
54         if (width < 2 || width > 16)
55         {
56             throw new IllegalArgumentException("'width' must be in the range [2, 16]");
57         }
58         if ((k.bitLength() >>> 16) != 0)
59         {
60             throw new IllegalArgumentException("'k' must have bitlength < 2^16");
61         }
62 
63         int[] wnaf = new int[k.bitLength() / width + 1];
64 
65         // 2^width and a mask and sign bit set accordingly
66         int pow2 = 1 << width;
67         int mask = pow2 - 1;
68         int sign = pow2 >>> 1;
69 
70         boolean carry = false;
71         int length = 0, pos = 0;
72 
73         while (pos <= k.bitLength())
74         {
75             if (k.testBit(pos) == carry)
76             {
77                 ++pos;
78                 continue;
79             }
80 
81             k = k.shiftRight(pos);
82 
83             int digit = k.intValue() & mask;
84             if (carry)
85             {
86                 ++digit;
87             }
88 
89             carry = (digit & sign) != 0;
90             if (carry)
91             {
92                 digit -= pow2;
93             }
94 
95             int zeroes = length > 0 ? pos - 1 : pos;
96             wnaf[length++] = (digit << 16) | zeroes;
97             pos = width;
98         }
99 
100         // Reduce the WNAF array to its actual length
101         if (wnaf.length > length)
102         {
103             wnaf = trim(wnaf, length);
104         }
105 
106         return wnaf;
107     }
108 
generateJSF(BigInteger g, BigInteger h)109     public static byte[] generateJSF(BigInteger g, BigInteger h)
110     {
111         int digits = Math.max(g.bitLength(), h.bitLength()) + 1;
112         byte[] jsf = new byte[digits];
113 
114         BigInteger k0 = g, k1 = h;
115         int j = 0, d0 = 0, d1 = 0;
116 
117         while (k0.signum() > 0 || k1.signum() > 0 || d0 > 0 || d1 > 0)
118         {
119             int n0 = (k0.intValue() + d0) & 7, n1 = (k1.intValue() + d1) & 7;
120 
121             int u0 = n0 & 1;
122             if (u0 != 0)
123             {
124                 u0 -= (n0 & 2);
125                 if ((n0 + u0) == 4 && (n1 & 3) == 2)
126                 {
127                     u0 = -u0;
128                 }
129             }
130 
131             int u1 = n1 & 1;
132             if (u1 != 0)
133             {
134                 u1 -= (n1 & 2);
135                 if ((n1 + u1) == 4 && (n0 & 3) == 2)
136                 {
137                     u1 = -u1;
138                 }
139             }
140 
141             if ((d0 << 1) == 1 + u0)
142             {
143                 d0 = 1 - d0;
144             }
145             if ((d1 << 1) == 1 + u1)
146             {
147                 d1 = 1 - d1;
148             }
149 
150             k0 = k0.shiftRight(1);
151             k1 = k1.shiftRight(1);
152 
153             jsf[j++] = (byte)((u0 << 4) | (u1 & 0xF));
154         }
155 
156         // Reduce the JSF array to its actual length
157         if (jsf.length > j)
158         {
159             jsf = trim(jsf, j);
160         }
161 
162         return jsf;
163     }
164 
generateNaf(BigInteger k)165     public static byte[] generateNaf(BigInteger k)
166     {
167         BigInteger _3k = k.shiftLeft(1).add(k);
168 
169         int digits = _3k.bitLength() - 1;
170         byte[] naf = new byte[digits];
171 
172         for (int i = 1; i <= digits; ++i)
173         {
174             boolean _3kBit = _3k.testBit(i);
175             boolean kBit = k.testBit(i);
176 
177             naf[i - 1] = (byte)(_3kBit == kBit ? 0 : kBit ? -1 : 1);
178         }
179 
180         return naf;
181     }
182 
183     /**
184      * Computes the Window NAF (non-adjacent Form) of an integer.
185      * @param width The width <code>w</code> of the Window NAF. The width is
186      * defined as the minimal number <code>w</code>, such that for any
187      * <code>w</code> consecutive digits in the resulting representation, at
188      * most one is non-zero.
189      * @param k The integer of which the Window NAF is computed.
190      * @return The Window NAF of the given width, such that the following holds:
191      * <code>k = &sum;<sub>i=0</sub><sup>l-1</sup> k<sub>i</sub>2<sup>i</sup>
192      * </code>, where the <code>k<sub>i</sub></code> denote the elements of the
193      * returned <code>byte[]</code>.
194      */
generateWindowNaf(int width, BigInteger k)195     public static byte[] generateWindowNaf(int width, BigInteger k)
196     {
197         if (width == 2)
198         {
199             return generateNaf(k);
200         }
201 
202         if (width < 2 || width > 8)
203         {
204             throw new IllegalArgumentException("'width' must be in the range [2, 8]");
205         }
206 
207         byte[] wnaf = new byte[k.bitLength() + 1];
208 
209         // 2^width and a mask and sign bit set accordingly
210         int pow2 = 1 << width;
211         int mask = pow2 - 1;
212         int sign = pow2 >>> 1;
213 
214         boolean carry = false;
215         int length = 0, pos = 0;
216 
217         while (pos <= k.bitLength())
218         {
219             if (k.testBit(pos) == carry)
220             {
221                 ++pos;
222                 continue;
223             }
224 
225             k = k.shiftRight(pos);
226 
227             int digit = k.intValue() & mask;
228             if (carry)
229             {
230                 ++digit;
231             }
232 
233             carry = (digit & sign) != 0;
234             if (carry)
235             {
236                 digit -= pow2;
237             }
238 
239             length += (length > 0) ? pos - 1 : pos;
240             wnaf[length++] = (byte)digit;
241             pos = width;
242         }
243 
244         // Reduce the WNAF array to its actual length
245         if (wnaf.length > length)
246         {
247             wnaf = trim(wnaf, length);
248         }
249 
250         return wnaf;
251     }
252 
getWNafPreCompInfo(PreCompInfo preCompInfo)253     public static WNafPreCompInfo getWNafPreCompInfo(PreCompInfo preCompInfo)
254     {
255         if ((preCompInfo != null) && (preCompInfo instanceof WNafPreCompInfo))
256         {
257             return (WNafPreCompInfo)preCompInfo;
258         }
259 
260         return new WNafPreCompInfo();
261     }
262 
263     /**
264      * Determine window width to use for a scalar multiplication of the given size.
265      *
266      * @param bits the bit-length of the scalar to multiply by
267      * @return the window size to use
268      */
getWindowSize(int bits)269     public static int getWindowSize(int bits)
270     {
271         return getWindowSize(bits, DEFAULT_WINDOW_SIZE_CUTOFFS);
272     }
273 
274     /**
275      * Determine window width to use for a scalar multiplication of the given size.
276      *
277      * @param bits the bit-length of the scalar to multiply by
278      * @param windowSizeCutoffs a monotonically increasing list of bit sizes at which to increment the window width
279      * @return the window size to use
280      */
getWindowSize(int bits, int[] windowSizeCutoffs)281     public static int getWindowSize(int bits, int[] windowSizeCutoffs)
282     {
283         int w = 0;
284         for (; w < windowSizeCutoffs.length; ++w)
285         {
286             if (bits < windowSizeCutoffs[w])
287             {
288                 break;
289             }
290         }
291         return w + 2;
292     }
293 
precompute(ECPoint p, int width, boolean includeNegated)294     public static WNafPreCompInfo precompute(ECPoint p, int width, boolean includeNegated)
295     {
296         ECCurve c = p.getCurve();
297         WNafPreCompInfo wnafPreCompInfo = getWNafPreCompInfo(c.getPreCompInfo(p));
298 
299         ECPoint[] preComp = wnafPreCompInfo.getPreComp();
300         if (preComp == null)
301         {
302             preComp = new ECPoint[]{ p };
303         }
304 
305         int preCompLen = preComp.length;
306         int reqPreCompLen = 1 << Math.max(0, width - 2);
307 
308         if (preCompLen < reqPreCompLen)
309         {
310             ECPoint twiceP = wnafPreCompInfo.getTwiceP();
311             if (twiceP == null)
312             {
313                 twiceP = preComp[0].twice().normalize();
314                 wnafPreCompInfo.setTwiceP(twiceP);
315             }
316 
317             preComp = resizeTable(preComp, reqPreCompLen);
318 
319             /*
320              * TODO Okeya/Sakurai paper has precomputation trick and  "Montgomery's Trick" to speed this up.
321              * Also, co-Z arithmetic could avoid the subsequent normalization too.
322              */
323             for (int i = preCompLen; i < reqPreCompLen; i++)
324             {
325                 /*
326                  * Compute the new ECPoints for the precomputation array. The values 1, 3, 5, ...,
327                  * 2^(width-1)-1 times p are computed
328                  */
329                 preComp[i] = twiceP.add(preComp[i - 1]);
330             }
331 
332             /*
333              * Having oft-used operands in affine form makes operations faster.
334              */
335             c.normalizeAll(preComp);
336         }
337 
338         wnafPreCompInfo.setPreComp(preComp);
339 
340         if (includeNegated)
341         {
342             ECPoint[] preCompNeg = wnafPreCompInfo.getPreCompNeg();
343 
344             int pos;
345             if (preCompNeg == null)
346             {
347                 pos = 0;
348                 preCompNeg = new ECPoint[reqPreCompLen];
349             }
350             else
351             {
352                 pos = preCompNeg.length;
353                 if (pos < reqPreCompLen)
354                 {
355                     preCompNeg = resizeTable(preCompNeg, reqPreCompLen);
356                 }
357             }
358 
359             while (pos < reqPreCompLen)
360             {
361                 preCompNeg[pos] = preComp[pos].negate();
362                 ++pos;
363             }
364 
365             wnafPreCompInfo.setPreCompNeg(preCompNeg);
366         }
367 
368         c.setPreCompInfo(p, wnafPreCompInfo);
369 
370         return wnafPreCompInfo;
371     }
372 
trim(byte[] a, int length)373     private static byte[] trim(byte[] a, int length)
374     {
375         byte[] result = new byte[length];
376         System.arraycopy(a, 0, result, 0, result.length);
377         return result;
378     }
379 
trim(int[] a, int length)380     private static int[] trim(int[] a, int length)
381     {
382         int[] result = new int[length];
383         System.arraycopy(a, 0, result, 0, result.length);
384         return result;
385     }
386 
resizeTable(ECPoint[] a, int length)387     private static ECPoint[] resizeTable(ECPoint[] a, int length)
388     {
389         ECPoint[] result = new ECPoint[length];
390         System.arraycopy(a, 0, result, 0, a.length);
391         return result;
392     }
393 }
394