/** * 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, BigInteger k, PreCompInfo preCompInfo) { WNafPreCompInfo wnafPreCompInfo; if ((preCompInfo != null) && (preCompInfo is 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 sbyte 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]; Array.Copy(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 sbyte[] wnaf = WindowNaf(width, k); int l = wnaf.Length; // Apply the Window NAF to p using the precomputed ECPoint values. ECPoint q = p.Curve.Infinity; 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; }