diff options
Diffstat (limited to 'repackaged/bcprov/src/main/java/com/android/org/bouncycastle/math/raw/Mod.java')
-rw-r--r-- | repackaged/bcprov/src/main/java/com/android/org/bouncycastle/math/raw/Mod.java | 578 |
1 files changed, 482 insertions, 96 deletions
diff --git a/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/math/raw/Mod.java b/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/math/raw/Mod.java index 7d0c48d7..80e45ca1 100644 --- a/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/math/raw/Mod.java +++ b/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/math/raw/Mod.java @@ -3,15 +3,51 @@ package com.android.org.bouncycastle.math.raw; import java.util.Random; -import com.android.org.bouncycastle.util.Pack; +import com.android.org.bouncycastle.util.Integers; + +/* + * Modular inversion as implemented in this class is based on the paper "Fast constant-time gcd + * computation and modular inversion" by Daniel J. Bernstein and Bo-Yin Yang. + */ /** * @hide This class is not part of the Android public SDK API */ public abstract class Mod { + private static final int M30 = 0x3FFFFFFF; + private static final long M32L = 0xFFFFFFFFL; + + /** @deprecated Will be removed. */ + public static void add(int[] p, int[] x, int[] y, int[] z) + { + int len = p.length; + int c = Nat.add(len, x, y, z); + if (c != 0) + { + Nat.subFrom(len, p, z); + } + } + + public static void checkedModOddInverse(int[] m, int[] x, int[] z) + { + if (0 == modOddInverse(m, x, z)) + { + throw new ArithmeticException("Inverse does not exist."); + } + } + + public static void checkedModOddInverseVar(int[] m, int[] x, int[] z) + { + if (!modOddInverseVar(m, x, z)) + { + throw new ArithmeticException("Inverse does not exist."); + } + } + public static int inverse32(int d) { +// assert (d & 1) == 1; // int x = d + (((d + 1) & 4) << 1); // d.x == 1 mod 2**4 int x = d; // d.x == 1 mod 2**3 x *= 2 - d * x; // d.x == 1 mod 2**6 @@ -22,72 +58,152 @@ public abstract class Mod return x; } - public static void invert(int[] p, int[] x, int[] z) + /** @deprecated Use {@link #checkedModOddInverseVar(int[], int[], int[])} instead. */ + public static void invert(int[] m, int[] x, int[] z) { - int len = p.length; - if (Nat.isZero(len, x)) - { - throw new IllegalArgumentException("'x' cannot be 0"); - } - if (Nat.isOne(len, x)) - { - System.arraycopy(x, 0, z, 0, len); - return; - } + checkedModOddInverseVar(m, x, z); + } - int[] u = Nat.copy(len, x); - int[] a = Nat.create(len); - a[0] = 1; - int ac = 0; + public static int modOddInverse(int[] m, int[] x, int[] z) + { + int len32 = m.length; +// assert len32 > 0; +// assert (m[0] & 1) != 0; +// assert m[len32 - 1] != 0; - if ((u[0] & 1) == 0) - { - ac = inversionStep(p, u, len, a, ac); - } - if (Nat.isOne(len, u)) + int bits = (len32 << 5) - Integers.numberOfLeadingZeros(m[len32 - 1]); + int len30 = (bits + 29) / 30; + + int[] t = new int[4]; + int[] D = new int[len30]; + int[] E = new int[len30]; + int[] F = new int[len30]; + int[] G = new int[len30]; + int[] M = new int[len30]; + + E[0] = 1; + encode30(bits, x, 0, G, 0); + encode30(bits, m, 0, M, 0); + System.arraycopy(M, 0, F, 0, len30); + + int eta = -1; + int m0Inv32 = inverse32(M[0]); + int maxDivsteps = getMaximumDivsteps(bits); + + for (int divSteps = 0; divSteps < maxDivsteps; divSteps += 30) { - inversionResult(p, ac, a, z); - return; + eta = divsteps30(eta, F[0], G[0], t); + updateDE30(len30, D, E, t, m0Inv32, M); + updateFG30(len30, F, G, t); } - int[] v = Nat.copy(len, p); - int[] b = Nat.create(len); - int bc = 0; + int signF = F[len30 - 1] >> 31; + cnegate30(len30, signF, F); - int uvLen = len; + /* + * D is in the range (-2.M, M). First, conditionally add M if D is negative, to bring it + * into the range (-M, M). Then normalize by conditionally negating (according to signF) + * and/or then adding M, to bring it into the range [0, M). + */ + cnormalize30(len30, signF, D, M); - for (;;) + decode30(bits, D, 0, z, 0); +// assert 0 != Nat.lessThan(len32, z, m); + + return Nat.equalTo(len30, F, 1) & Nat.equalToZero(len30, G); + } + + public static boolean modOddInverseVar(int[] m, int[] x, int[] z) + { + int len32 = m.length; +// assert len32 > 0; +// assert (m[0] & 1) != 0; +// assert m[len32 - 1] != 0; + + int bits = (len32 << 5) - Integers.numberOfLeadingZeros(m[len32 - 1]); + int len30 = (bits + 29) / 30; + + int[] t = new int[4]; + int[] D = new int[len30]; + int[] E = new int[len30]; + int[] F = new int[len30]; + int[] G = new int[len30]; + int[] M = new int[len30]; + + E[0] = 1; + encode30(bits, x, 0, G, 0); + encode30(bits, m, 0, M, 0); + System.arraycopy(M, 0, F, 0, len30); + + int clzG = Integers.numberOfLeadingZeros(G[len30 - 1] | 1) - (len30 * 30 + 2 - bits); + int eta = -1 - clzG; + int lenDE = len30, lenFG = len30; + int m0Inv32 = inverse32(M[0]); + int maxDivsteps = getMaximumDivsteps(bits); + + int divsteps = 0; + while (!Nat.isZero(lenFG, G)) { - while (u[uvLen - 1] == 0 && v[uvLen - 1] == 0) + if (divsteps >= maxDivsteps) { - --uvLen; + return false; } - if (Nat.gte(uvLen, u, v)) - { - Nat.subFrom(uvLen, v, u); -// assert (u[0] & 1) == 0; - ac += Nat.subFrom(len, b, a) - bc; - ac = inversionStep(p, u, uvLen, a, ac); - if (Nat.isOne(uvLen, u)) - { - inversionResult(p, ac, a, z); - return; - } - } - else + divsteps += 30; + + eta = divsteps30Var(eta, F[0], G[0], t); + updateDE30(lenDE, D, E, t, m0Inv32, M); + updateFG30(lenFG, F, G, t); + + int fn = F[lenFG - 1]; + int gn = G[lenFG - 1]; + + int cond = (lenFG - 2) >> 31; + cond |= fn ^ (fn >> 31); + cond |= gn ^ (gn >> 31); + + if (cond == 0) { - Nat.subFrom(uvLen, u, v); -// assert (v[0] & 1) == 0; - bc += Nat.subFrom(len, a, b) - ac; - bc = inversionStep(p, v, uvLen, b, bc); - if (Nat.isOne(uvLen, v)) - { - inversionResult(p, bc, b, z); - return; - } + F[lenFG - 2] |= fn << 30; + G[lenFG - 2] |= gn << 30; + --lenFG; } } + + int signF = F[lenFG - 1] >> 31; + + /* + * D is in the range (-2.M, M). First, conditionally add M if D is negative, to bring it + * into the range (-M, M). Then normalize by conditionally negating (according to signF) + * and/or then adding M, to bring it into the range [0, M). + */ + int signD = D[lenDE - 1] >> 31; + if (signD < 0) + { + signD = add30(lenDE, D, M); + } + if (signF < 0) + { + signD = negate30(lenDE, D); + signF = negate30(lenFG, F); + } +// assert 0 == signF; + + if (!Nat.isOne(lenFG, F)) + { + return false; + } + + if (signD < 0) + { + signD = add30(lenDE, D, M); + } +// assert 0 == signD; + + decode30(bits, D, 0, z, 0); +// assert !Nat.gte(len32, z, m); + + return true; } public static int[] random(int[] p) @@ -116,88 +232,358 @@ public abstract class Mod return s; } - public static void add(int[] p, int[] x, int[] y, int[] z) + /** @deprecated Will be removed. */ + public static void subtract(int[] p, int[] x, int[] y, int[] z) { int len = p.length; - int c = Nat.add(len, x, y, z); + int c = Nat.sub(len, x, y, z); if (c != 0) { - Nat.subFrom(len, p, z); + Nat.addTo(len, p, z); } } - public static void subtract(int[] p, int[] x, int[] y, int[] z) + private static int add30(int len30, int[] D, int[] M) { - int len = p.length; - int c = Nat.sub(len, x, y, z); - if (c != 0) +// assert len30 > 0; +// assert D.length >= len30; +// assert M.length >= len30; + + int c = 0, last = len30 - 1; + for (int i = 0; i < last; ++i) { - Nat.addTo(len, p, z); + c += D[i] + M[i]; + D[i] = c & M30; c >>= 30; } + c += D[last] + M[last]; + D[last] = c; c >>= 30; + return c; } - private static void inversionResult(int[] p, int ac, int[] a, int[] z) + private static void cnegate30(int len30, int cond, int[] D) { - if (ac < 0) +// assert len30 > 0; +// assert D.length >= len30; + + int c = 0, last = len30 - 1; + for (int i = 0; i < last; ++i) { - Nat.add(p.length, a, p, z); + c += (D[i] ^ cond) - cond; + D[i] = c & M30; c >>= 30; } - else + c += (D[last] ^ cond) - cond; + D[last] = c; + } + + private static void cnormalize30(int len30, int condNegate, int[] D, int[] M) + { +// assert len30 > 0; +// assert D.length >= len30; +// assert M.length >= len30; + + int last = len30 - 1; + { - System.arraycopy(a, 0, z, 0, p.length); + int c = 0, condAdd = D[last] >> 31; + for (int i = 0; i < last; ++i) + { + int di = D[i] + (M[i] & condAdd); + di = (di ^ condNegate) - condNegate; + c += di; D[i] = c & M30; c >>= 30; + } + { + int di = D[last] + (M[last] & condAdd); + di = (di ^ condNegate) - condNegate; + c += di; D[last] = c; + } + } + + { + int c = 0, condAdd = D[last] >> 31; + for (int i = 0; i < last; ++i) + { + int di = D[i] + (M[i] & condAdd); + c += di; D[i] = c & M30; c >>= 30; + } + { + int di = D[last] + (M[last] & condAdd); + c += di; D[last] = c; + } +// assert c >> 30 == 0; } } - private static int inversionStep(int[] p, int[] u, int uLen, int[] x, int xc) + private static void decode30(int bits, int[] x, int xOff, int[] z, int zOff) { - int len = p.length; - int count = 0; - while (u[0] == 0) +// assert bits > 0; +// assert x != z; + + int avail = 0; + long data = 0L; + + while (bits > 0) { - Nat.shiftDownWord(uLen, u, 0); - count += 32; + while (avail < Math.min(32, bits)) + { + data |= (long)x[xOff++] << avail; + avail += 30; + } + + z[zOff++] = (int)data; data >>>= 32; + avail -= 32; + bits -= 32; + } + } + + private static int divsteps30(int eta, int f0, int g0, int[] t) + { + int u = 1, v = 0, q = 0, r = 1; + int f = f0, g = g0; + + for (int i = 0; i < 30; ++i) + { +// assert (f & 1) == 1; +// assert (u * f0 + v * g0) == f << i; +// assert (q * f0 + r * g0) == g << i; + + int c1 = eta >> 31; + int c2 = -(g & 1); + + int x = (f ^ c1) - c1; + int y = (u ^ c1) - c1; + int z = (v ^ c1) - c1; + + g += x & c2; + q += y & c2; + r += z & c2; + + c1 &= c2; + eta = (eta ^ c1) - (c1 + 1); + + f += g & c1; + u += q & c1; + v += r & c1; + + g >>= 1; + u <<= 1; + v <<= 1; } + t[0] = u; + t[1] = v; + t[2] = q; + t[3] = r; + + return eta; + } + + private static int divsteps30Var(int eta, int f0, int g0, int[] t) + { + int u = 1, v = 0, q = 0, r = 1; + int f = f0, g = g0, m, w, x, y, z; + int i = 30, limit, zeros; + + for (;;) { - int zeroes = getTrailingZeroes(u[0]); - if (zeroes > 0) + // Use a sentinel bit to count zeros only up to i. + zeros = Integers.numberOfTrailingZeros(g | (-1 << i)); + + g >>= zeros; + u <<= zeros; + v <<= zeros; + eta -= zeros; + i -= zeros; + + if (i <= 0) + { + break; + } + +// assert (f & 1) == 1; +// assert (g & 1) == 1; +// assert (u * f0 + v * g0) == f << (30 - i); +// assert (q * f0 + r * g0) == g << (30 - i); + + if (eta < 0) { - Nat.shiftDownBits(uLen, u, zeroes, 0); - count += zeroes; + eta = -eta; + x = f; f = g; g = -x; + y = u; u = q; q = -y; + z = v; v = r; r = -z; + + // Handle up to 6 divsteps at once, subject to eta and i. + limit = (eta + 1) > i ? i : (eta + 1); + m = (-1 >>> (32 - limit)) & 63; + + w = (f * g * (f * f - 2)) & m; + } + else + { + // Handle up to 4 divsteps at once, subject to eta and i. + limit = (eta + 1) > i ? i : (eta + 1); + m = (-1 >>> (32 - limit)) & 15; + + w = f + (((f + 1) & 4) << 1); + w = (-w * g) & m; } + + g += f * w; + q += u * w; + r += v * w; + +// assert (g & m) == 0; } - for (int i = 0; i < count; ++i) + t[0] = u; + t[1] = v; + t[2] = q; + t[3] = r; + + return eta; + } + + private static void encode30(int bits, int[] x, int xOff, int[] z, int zOff) + { +// assert bits > 0; +// assert x != z; + + int avail = 0; + long data = 0L; + + while (bits > 0) { - if ((x[0] & 1) != 0) + if (avail < Math.min(30, bits)) { - if (xc < 0) - { - xc += Nat.addTo(len, p, x); - } - else - { - xc += Nat.subFrom(len, p, x); - } + data |= (x[xOff++] & M32L) << avail; + avail += 32; } -// assert xc == 0 || xc == 1; - Nat.shiftDownBit(len, x, xc); + z[zOff++] = (int)data & M30; data >>>= 30; + avail -= 30; + bits -= 30; } - - return xc; } - private static int getTrailingZeroes(int x) + private static int getMaximumDivsteps(int bits) + { + return (49 * bits + (bits < 46 ? 80 : 47)) / 17; + } + + private static int negate30(int len30, int[] D) { -// assert x != 0; +// assert len30 > 0; +// assert D.length >= len30; - int count = 0; - while ((x & 1) == 0) + int c = 0, last = len30 - 1; + for (int i = 0; i < last; ++i) { - x >>>= 1; - ++count; + c -= D[i]; + D[i] = c & M30; c >>= 30; } - return count; + c -= D[last]; + D[last] = c; c >>= 30; + return c; + } + + private static void updateDE30(int len30, int[] D, int[] E, int[] t, int m0Inv32, int[] M) + { +// assert len30 > 0; +// assert D.length >= len30; +// assert E.length >= len30; +// assert M.length >= len30; +// assert m0Inv32 * M[0] == 1; + + final int u = t[0], v = t[1], q = t[2], r = t[3]; + int di, ei, i, md, me, mi, sd, se; + long cd, ce; + + /* + * We accept D (E) in the range (-2.M, M) and conceptually add the modulus to the input + * value if it is initially negative. Instead of adding it explicitly, we add u and/or v (q + * and/or r) to md (me). + */ + sd = D[len30 - 1] >> 31; + se = E[len30 - 1] >> 31; + + md = (u & sd) + (v & se); + me = (q & sd) + (r & se); + + mi = M[0]; + di = D[0]; + ei = E[0]; + + cd = (long)u * di + (long)v * ei; + ce = (long)q * di + (long)r * ei; + + /* + * Subtract from md/me an extra term in the range [0, 2^30) such that the low 30 bits of the + * intermediate D/E values will be 0, allowing clean division by 2^30. The final D/E are + * thus in the range (-2.M, M), consistent with the input constraint. + */ + md -= (m0Inv32 * (int)cd + md) & M30; + me -= (m0Inv32 * (int)ce + me) & M30; + + cd += (long)mi * md; + ce += (long)mi * me; + +// assert ((int)cd & M30) == 0; +// assert ((int)ce & M30) == 0; + + cd >>= 30; + ce >>= 30; + + for (i = 1; i < len30; ++i) + { + mi = M[i]; + di = D[i]; + ei = E[i]; + + cd += (long)u * di + (long)v * ei + (long)mi * md; + ce += (long)q * di + (long)r * ei + (long)mi * me; + + D[i - 1] = (int)cd & M30; cd >>= 30; + E[i - 1] = (int)ce & M30; ce >>= 30; + } + + D[len30 - 1] = (int)cd; + E[len30 - 1] = (int)ce; + } + + private static void updateFG30(int len30, int[] F, int[] G, int[] t) + { +// assert len30 > 0; +// assert F.length >= len30; +// assert G.length >= len30; + + final int u = t[0], v = t[1], q = t[2], r = t[3]; + int fi, gi, i; + long cf, cg; + + fi = F[0]; + gi = G[0]; + + cf = (long)u * fi + (long)v * gi; + cg = (long)q * fi + (long)r * gi; + +// assert ((int)cf & M30) == 0; +// assert ((int)cg & M30) == 0; + + cf >>= 30; + cg >>= 30; + + for (i = 1; i < len30; ++i) + { + fi = F[i]; + gi = G[i]; + + cf += (long)u * fi + (long)v * gi; + cg += (long)q * fi + (long)r * gi; + + F[i - 1] = (int)cf & M30; cf >>= 30; + G[i - 1] = (int)cg & M30; cg >>= 30; + } + + F[len30 - 1] = (int)cf; + G[len30 - 1] = (int)cg; } } |