/** * Multiplies <code>this</code> by an integer <code>k</code> using the Window NAF method. * * @param k The integer by which <code>this</code> is multiplied. * @return A new <code>ECPoint</code> which equals <code>this</code> multiplied by <code>k</code>. */ public ECPoint multiply(ECPoint p, BigIntegerCrypto k, PreCompInfo preCompInfo) { WNafPreCompInfo wnafPreCompInfo; if ((preCompInfo != null) && (preCompInfo instanceof WNafPreCompInfo)) { wnafPreCompInfo = (WNafPreCompInfo) preCompInfo; } else { // Ignore empty PreCompInfo or PreCompInfo of incorrect type wnafPreCompInfo = new WNafPreCompInfo(); } // floor(log2(k)) int m = k.bitLength(); // width of the Window NAF byte width; // Required length of precomputation array int reqPreCompLen; // Determine optimal width and corresponding length of precomputation // array based on literature values if (m < 13) { width = 2; reqPreCompLen = 1; } else { if (m < 41) { width = 3; reqPreCompLen = 2; } else { if (m < 121) { width = 4; reqPreCompLen = 4; } else { if (m < 337) { width = 5; reqPreCompLen = 8; } else { if (m < 897) { width = 6; reqPreCompLen = 16; } else { if (m < 2305) { width = 7; reqPreCompLen = 32; } else { width = 8; reqPreCompLen = 127; } } } } } } // The length of the precomputation array int preCompLen = 1; ECPoint[] preComp = wnafPreCompInfo.getPreComp(); ECPoint twiceP = wnafPreCompInfo.getTwiceP(); // Check if the precomputed ECPoints already exist if (preComp == null) { // Precomputation must be performed from scratch, create an empty // precomputation array of desired length preComp = new ECPoint[] {p}; } else { // Take the already precomputed ECPoints to start with preCompLen = preComp.length; } if (twiceP == null) { // Compute twice(p) twiceP = p.twice(); } if (preCompLen < reqPreCompLen) { // Precomputation array must be made bigger, copy existing preComp // array into the larger new preComp array ECPoint[] oldPreComp = preComp; preComp = new ECPoint[reqPreCompLen]; System.arraycopy(oldPreComp, 0, preComp, 0, preCompLen); for (int i = preCompLen; i < reqPreCompLen; i++) { // Compute the new ECPoints for the precomputation array. // The values 1, 3, 5, ..., 2^(width-1)-1 times p are // computed preComp[i] = twiceP.add(preComp[i - 1]); } } // Compute the Window NAF of the desired width byte[] wnaf = windowNaf(width, k); int l = wnaf.length; // Apply the Window NAF to p using the precomputed ECPoint values. ECPoint q = p.getCurve().getInfinity(); for (int i = l - 1; i >= 0; i--) { q = q.twice(); if (wnaf[i] != 0) { if (wnaf[i] > 0) { q = q.add(preComp[(wnaf[i] - 1) / 2]); } else { // wnaf[i] < 0 q = q.subtract(preComp[(-wnaf[i] - 1) / 2]); } } } // Set PreCompInfo in ECPoint, such that it is available for next // multiplication. wnafPreCompInfo.setPreComp(preComp); wnafPreCompInfo.setTwiceP(twiceP); p.setPreCompInfo(wnafPreCompInfo); return q; }
/** * Computes the Window NAF (non-adjacent Form) of an integer. * * @param width The width <code>w</code> of the Window NAF. The width is defined as the minimal * number <code>w</code>, such that for any <code>w</code> consecutive digits in the resulting * representation, at most one is non-zero. * @param k The integer of which the Window NAF is computed. * @return The Window NAF of the given width, such that the following holds: <code> * k = ∑<sub>i=0</sub><sup>l-1</sup> k<sub>i</sub>2<sup>i</sup> * </code>, where the <code>k<sub>i</sub></code> denote the elements of the returned <code>byte[] * </code>. */ public byte[] windowNaf(byte width, BigIntegerCrypto k) { // The window NAF is at most 1 element longer than the binary // representation of the integer k. byte can be used instead of short or // int unless the window width is larger than 8. For larger width use // short or int. However, a width of more than 8 is not efficient for // m = log2(q) smaller than 2305 Bits. Note: Values for m larger than // 1000 Bits are currently not used in practice. byte[] wnaf = new byte[k.bitLength() + 1]; // 2^width as short and BigInteger short pow2wB = (short) (1 << width); BigIntegerCrypto pow2wBI = BigIntegerCrypto.valueOf(pow2wB); int i = 0; // The actual length of the WNAF int length = 0; // while k >= 1 while (k.signum() > 0) { // if k is odd if (k.testBit(0)) { // k mod 2^width BigIntegerCrypto remainder = k.mod(pow2wBI); // if remainder > 2^(width - 1) - 1 if (remainder.testBit(width - 1)) { wnaf[i] = (byte) (remainder.intValue() - pow2wB); } else { wnaf[i] = (byte) remainder.intValue(); } // wnaf[i] is now in [-2^(width-1), 2^(width-1)-1] k = k.subtract(BigIntegerCrypto.valueOf(wnaf[i])); length = i; } else { wnaf[i] = 0; } // k = k/2 k = k.shiftRight(1); i++; } length++; // Reduce the WNAF array to its actual length byte[] wnafShort = new byte[length]; System.arraycopy(wnaf, 0, wnafShort, 0, length); return wnafShort; }