public LongArray ModMultiply(LongArray other, int m, int[] ks) { /* * Find out the degree of each argument and handle the zero cases */ int aDeg = Degree(); if (aDeg == 0) { return this; } int bDeg = other.Degree(); if (bDeg == 0) { return other; } /* * Swap if necessary so that A is the smaller argument */ LongArray A = this, B = other; if (aDeg > bDeg) { A = other; B = this; int tmp = aDeg; aDeg = bDeg; bDeg = tmp; } /* * Establish the word lengths of the arguments and result */ int aLen = (int)((uint)(aDeg + 63) >> 6); int bLen = (int)((uint)(bDeg + 63) >> 6); int cLen = (int)((uint)(aDeg + bDeg + 62) >> 6); if (aLen == 1) { long a0 = A.m_ints[0]; if (a0 == 1L) { return B; } /* * Fast path for small A, with performance dependent only on the number of set bits */ long[] c0 = new long[cLen]; MultiplyWord(a0, B.m_ints, bLen, c0, 0); /* * Reduce the raw answer against the reduction coefficients */ return ReduceResult(c0, 0, cLen, m, ks); } /* * Determine if B will get bigger during shifting */ int bMax = (int)((uint)(bDeg + 7 + 63) >> 6); /* * Lookup table for the offset of each B in the tables */ int[] ti = new int[16]; /* * Precompute table of all 4-bit products of B */ long[] T0 = new long[bMax << 4]; int tOff = bMax; ti[1] = tOff; Array.Copy(B.m_ints, 0, T0, tOff, bLen); for (int i = 2; i < 16; ++i) { ti[i] = (tOff += bMax); if ((i & 1) == 0) { ShiftUp(T0, (int)((uint)tOff >> 1), T0, tOff, bMax, 1); } else { Add(T0, bMax, T0, tOff - bMax, T0, tOff, bMax); } } /* * Second table with all 4-bit products of B shifted 4 bits */ long[] T1 = new long[T0.Length]; ShiftUp(T0, 0, T1, 0, T0.Length, 4); // ShiftUp(T0, bMax, T1, bMax, tOff, 4); long[] a = A.m_ints; long[] c = new long[cLen << 3]; int MASK = 0xF; /* * Lopez-Dahab (Modified) algorithm */ for (int aPos = 0; aPos < aLen; ++aPos) { long aVal = a[aPos]; int cOff = aPos; for (;;) { int u = (int)aVal & MASK; aVal = (long)((ulong)aVal >> 4); int v = (int)aVal & MASK; AddBoth(c, cOff, T0, ti[u], T1, ti[v], bMax); aVal = (long)((ulong)aVal >> 4); if (aVal == 0L) { break; } cOff += cLen; } } { int cOff = c.Length; while ((cOff -= cLen) != 0) { AddShiftedUp(c, cOff - cLen, c, cOff, cLen, 8); } } /* * Finally the raw answer is collected, reduce it against the reduction coefficients */ return ReduceResult(c, 0, cLen, m, ks); }
public LongArray ModMultiplyAlt(LongArray other, int m, int[] ks) { /* * Find out the degree of each argument and handle the zero cases */ int aDeg = Degree(); if (aDeg == 0) { return this; } int bDeg = other.Degree(); if (bDeg == 0) { return other; } /* * Swap if necessary so that A is the smaller argument */ LongArray A = this, B = other; if (aDeg > bDeg) { A = other; B = this; int tmp = aDeg; aDeg = bDeg; bDeg = tmp; } /* * Establish the word lengths of the arguments and result */ int aLen = (int)((uint)(aDeg + 63) >> 6); int bLen = (int)((uint)(bDeg + 63) >> 6); int cLen = (int)((uint)(aDeg + bDeg + 62) >> 6); if (aLen == 1) { long a0 = A.m_ints[0]; if (a0 == 1L) { return B; } /* * Fast path for small A, with performance dependent only on the number of set bits */ long[] c0 = new long[cLen]; MultiplyWord(a0, B.m_ints, bLen, c0, 0); /* * Reduce the raw answer against the reduction coefficients */ return ReduceResult(c0, 0, cLen, m, ks); } // NOTE: This works, but is slower than width 4 processing // if (aLen == 2) // { // /* // * Use common-multiplicand optimization to save ~1/4 of the adds // */ // long a1 = A.m_ints[0], a2 = A.m_ints[1]; // long aa = a1 & a2; a1 ^= aa; a2 ^= aa; // // long[] b = B.m_ints; // long[] c = new long[cLen]; // multiplyWord(aa, b, bLen, c, 1); // add(c, 0, c, 1, cLen - 1); // multiplyWord(a1, b, bLen, c, 0); // multiplyWord(a2, b, bLen, c, 1); // // /* // * Reduce the raw answer against the reduction coefficients // */ // return ReduceResult(c, 0, cLen, m, ks); // } /* * Determine the parameters of the Interleaved window algorithm: the 'width' in bits to * process together, the number of evaluation 'positions' implied by that width, and the * 'top' position at which the regular window algorithm stops. */ int width, positions, top, banks; // NOTE: width 4 is the fastest over the entire range of sizes used in current crypto // width = 1; positions = 64; top = 64; banks = 4; // width = 2; positions = 32; top = 64; banks = 4; // width = 3; positions = 21; top = 63; banks = 3; width = 4; positions = 16; top = 64; banks = 8; // width = 5; positions = 13; top = 65; banks = 7; // width = 7; positions = 9; top = 63; banks = 9; // width = 8; positions = 8; top = 64; banks = 8; /* * Determine if B will get bigger during shifting */ int shifts = top < 64 ? positions : positions - 1; int bMax = (int)((uint)(bDeg + shifts + 63) >> 6); int bTotal = bMax * banks, stride = width * banks; /* * Create a single temporary buffer, with an offset table to find the positions of things in it */ int[] ci = new int[1 << width]; int cTotal = aLen; { ci[0] = cTotal; cTotal += bTotal; ci[1] = cTotal; for (int i = 2; i < ci.Length; ++i) { cTotal += cLen; ci[i] = cTotal; } cTotal += cLen; } // NOTE: Provide a safe dump for "high zeroes" since we are adding 'bMax' and not 'bLen' ++cTotal; long[] c = new long[cTotal]; // Prepare A in Interleaved form, according to the chosen width Interleave(A.m_ints, 0, c, 0, aLen, width); // Make a working copy of B, since we will be shifting it { int bOff = aLen; Array.Copy(B.m_ints, 0, c, bOff, bLen); for (int bank = 1; bank < banks; ++bank) { ShiftUp(c, aLen, c, bOff += bMax, bMax, bank); } } /* * The main loop analyzes the Interleaved windows in A, and for each non-zero window * a single word-array XOR is performed to a carefully selected slice of 'c'. The loop is * breadth-first, checking the lowest window in each word, then looping again for the * next higher window position. */ int MASK = (1 << width) - 1; int k = 0; for (;;) { int aPos = 0; do { long aVal = (long)((ulong)c[aPos] >> k); int bank = 0, bOff = aLen; for (;;) { int index = (int)(aVal) & MASK; if (index != 0) { /* * Add to a 'c' buffer based on the bit-pattern of 'index'. Since A is in * Interleaved form, the bits represent the current B shifted by 0, 'positions', * 'positions' * 2, ..., 'positions' * ('width' - 1) */ Add(c, aPos + ci[index], c, bOff, bMax); } if (++bank == banks) { break; } bOff += bMax; aVal = (long)((ulong)aVal >> width); } } while (++aPos < aLen); if ((k += stride) >= top) { if (k >= 64) { break; } /* * Adjustment for window setups with top == 63, the final bit (if any) is processed * as the top-bit of a window */ k = 64 - width; MASK &= MASK << (top - k); } /* * After each position has been checked for all words of A, B is shifted up 1 place */ ShiftUp(c, aLen, bTotal, banks); } int ciPos = ci.Length; while (--ciPos > 1) { if ((ciPos & 1L) == 0L) { /* * For even numbers, shift contents and add to the half-position */ AddShiftedUp(c, ci[(uint)ciPos >> 1], c, ci[ciPos], cLen, positions); } else { /* * For odd numbers, 'distribute' contents to the result and the next-lowest position */ Distribute(c, ci[ciPos], ci[ciPos - 1], ci[1], cLen); } } /* * Finally the raw answer is collected, reduce it against the reduction coefficients */ return ReduceResult(c, ci[1], cLen, m, ks); }
public LongArray ModMultiplyAlt(LongArray other, int m, int[] ks) { int num = Degree(); if (num == 0) { return(this); } int num2 = other.Degree(); if (num2 == 0) { return(other); } LongArray longArray = this; LongArray longArray2 = other; if (num > num2) { longArray = other; longArray2 = this; int num3 = num; num = num2; num2 = num3; } int num4 = (int)((uint)(num + 63) >> 6); int num5 = (int)((uint)(num2 + 63) >> 6); int num6 = (int)((uint)(num + num2 + 62) >> 6); if (num4 == 1) { long num7 = longArray.m_ints[0]; if (num7 == 1) { return(longArray2); } long[] array = new long[num6]; MultiplyWord(num7, longArray2.m_ints, num5, array, 0); return(ReduceResult(array, 0, num6, m, ks)); } int num8 = 4; int num9 = 16; int num10 = 64; int num11 = 8; int num12 = ((num10 < 64) ? num9 : (num9 - 1)); int num13 = (int)((uint)(num2 + num12 + 63) >> 6); int num14 = num13 * num11; int num15 = num8 * num11; int[] array2 = new int[1 << num8]; int num16 = (array2[1] = (array2[0] = num4) + num14); for (int i = 2; i < array2.Length; i++) { num16 = (array2[i] = num16 + num6); } num16 += num6; num16++; long[] array3 = new long[num16]; Interleave(longArray.m_ints, 0, array3, 0, num4, num8); int num17 = num4; global::System.Array.Copy((global::System.Array)longArray2.m_ints, 0, (global::System.Array)array3, num17, num5); for (int j = 1; j < num11; j++) { ShiftUp(array3, num4, array3, num17 += num13, num13, j); } int num18 = (1 << num8) - 1; int num19 = 0; while (true) { int num20 = 0; do { long num21 = (long)((ulong)array3[num20] >> num19); int num22 = 0; int num23 = num4; while (true) { int num24 = (int)num21 & num18; if (num24 != 0) { Add(array3, num20 + array2[num24], array3, num23, num13); } if (++num22 == num11) { break; } num23 += num13; num21 = (long)((ulong)num21 >> num8); } }while (++num20 < num4); if ((num19 += num15) >= num10) { if (num19 >= 64) { break; } num19 = 64 - num8; num18 &= num18 << num10 - num19; } ShiftUp(array3, num4, num14, num11); } int num25 = array2.Length; while (--num25 > 1) { if (((ulong)num25 & 1uL) == 0) { AddShiftedUp(array3, array2[(uint)num25 >> 1], array3, array2[num25], num6, num9); } else { Distribute(array3, array2[num25], array2[num25 - 1], array2[1], num6); } } return(ReduceResult(array3, array2[1], num6, m, ks)); }
public LongArray Multiply(LongArray other, int m, int[] ks) { int num = Degree(); if (num == 0) { return(this); } int num2 = other.Degree(); if (num2 == 0) { return(other); } LongArray longArray = this; LongArray longArray2 = other; if (num > num2) { longArray = other; longArray2 = this; int num3 = num; num = num2; num2 = num3; } int num4 = (int)((uint)(num + 63) >> 6); int num5 = (int)((uint)(num2 + 63) >> 6); int num6 = (int)((uint)(num + num2 + 62) >> 6); if (num4 == 1) { long num7 = longArray.m_ints[0]; if (num7 == 1) { return(longArray2); } long[] array = new long[num6]; MultiplyWord(num7, longArray2.m_ints, num5, array, 0); return(new LongArray(array, 0, num6)); } int num8 = (int)((uint)(num2 + 7 + 63) >> 6); int[] array2 = new int[16]; long[] array3 = new long[num8 << 4]; int num9 = (array2[1] = num8); global::System.Array.Copy((global::System.Array)longArray2.m_ints, 0, (global::System.Array)array3, num9, num5); for (int i = 2; i < 16; i++) { num9 = (array2[i] = num9 + num8); if ((i & 1) == 0) { ShiftUp(array3, (int)((uint)num9 >> 1), array3, num9, num8, 1); } else { Add(array3, num8, array3, num9 - num8, array3, num9, num8); } } long[] array4 = new long[array3.Length]; ShiftUp(array3, 0, array4, 0, array3.Length, 4); long[] ints = longArray.m_ints; long[] array5 = new long[num6 << 3]; int num10 = 15; for (int j = 0; j < num4; j++) { long num11 = ints[j]; int num12 = j; while (true) { int num13 = (int)num11 & num10; num11 = (long)((ulong)num11 >> 4); int num14 = (int)num11 & num10; AddBoth(array5, num12, array3, array2[num13], array4, array2[num14], num8); num11 = (long)((ulong)num11 >> 4); if (num11 == 0) { break; } num12 += num6; } } int num15 = array5.Length; while ((num15 -= num6) != 0) { AddShiftedUp(array5, num15 - num6, array5, num15, num6, 8); } return(new LongArray(array5, 0, num6)); }
public LongArray ModMultiplyLD(LongArray other, int m, int[] ks) { int num = Degree(); if (num == 0) { return(this); } int num2 = other.Degree(); if (num2 == 0) { return(other); } LongArray longArray = this; LongArray longArray2 = other; if (num > num2) { longArray = other; longArray2 = this; int num3 = num; num = num2; num2 = num3; } int num4 = (int)((uint)(num + 63) >> 6); int num5 = (int)((uint)(num2 + 63) >> 6); int num6 = (int)((uint)(num + num2 + 62) >> 6); if (num4 == 1) { long num7 = longArray.m_ints[0]; if (num7 == 1) { return(longArray2); } long[] array = new long[num6]; MultiplyWord(num7, longArray2.m_ints, num5, array, 0); return(ReduceResult(array, 0, num6, m, ks)); } int num8 = (int)((uint)(num2 + 7 + 63) >> 6); int[] array2 = new int[16]; long[] array3 = new long[num8 << 4]; int num9 = (array2[1] = num8); global::System.Array.Copy((global::System.Array)longArray2.m_ints, 0, (global::System.Array)array3, num9, num5); for (int i = 2; i < 16; i++) { num9 = (array2[i] = num9 + num8); if ((i & 1) == 0) { ShiftUp(array3, (int)((uint)num9 >> 1), array3, num9, num8, 1); } else { Add(array3, num8, array3, num9 - num8, array3, num9, num8); } } long[] array4 = new long[array3.Length]; ShiftUp(array3, 0, array4, 0, array3.Length, 4); long[] ints = longArray.m_ints; long[] array5 = new long[num6]; int num10 = 15; for (int num11 = 56; num11 >= 0; num11 -= 8) { for (int j = 1; j < num4; j += 2) { int num12 = (int)((ulong)ints[j] >> num11); int num13 = num12 & num10; int num14 = (int)((uint)num12 >> 4) & num10; AddBoth(array5, j - 1, array3, array2[num13], array4, array2[num14], num8); } ShiftUp(array5, 0, num6, 8); } for (int num15 = 56; num15 >= 0; num15 -= 8) { for (int k = 0; k < num4; k += 2) { int num16 = (int)((ulong)ints[k] >> num15); int num17 = num16 & num10; int num18 = (int)((uint)num16 >> 4) & num10; AddBoth(array5, k, array3, array2[num17], array4, array2[num18], num8); } if (num15 > 0) { ShiftUp(array5, 0, num6, 8); } } return(ReduceResult(array5, 0, num6, m, ks)); }