package org.bouncycastle.math.raw; import java.util.Random; import org.bouncycastle.util.Pack; public abstract class Mod { public static int inverse32(int d) { // 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 x *= 2 - d * x; // d.x == 1 mod 2**12 x *= 2 - d * x; // d.x == 1 mod 2**24 x *= 2 - d * x; // d.x == 1 mod 2**48 // assert d * x == 1; return x; } public static void invert(int[] p, 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; } int[] u = Nat.copy(len, x); int[] a = Nat.create(len); a[0] = 1; int ac = 0; if ((u[0] & 1) == 0) { ac = inversionStep(p, u, len, a, ac); } if (Nat.isOne(len, u)) { inversionResult(p, ac, a, z); return; } int[] v = Nat.copy(len, p); int[] b = Nat.create(len); int bc = 0; int uvLen = len; for (;;) { while (u[uvLen - 1] == 0 && v[uvLen - 1] == 0) { --uvLen; } 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 { 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; } } } } public static int[] random(int[] p) { int len = p.length; Random rand = new Random(); int[] s = Nat.create(len); int m = p[len - 1]; m |= m >>> 1; m |= m >>> 2; m |= m >>> 4; m |= m >>> 8; m |= m >>> 16; do { for (int i = 0; i != len; i++) { s[i] = rand.nextInt(); } s[len - 1] &= m; } while (Nat.gte(len, s, p)); return s; } 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 subtract(int[] p, int[] x, int[] y, int[] z) { int len = p.length; int c = Nat.sub(len, x, y, z); if (c != 0) { Nat.addTo(len, p, z); } } private static void inversionResult(int[] p, int ac, int[] a, int[] z) { if (ac < 0) { Nat.add(p.length, a, p, z); } else { System.arraycopy(a, 0, z, 0, p.length); } } private static int inversionStep(int[] p, int[] u, int uLen, int[] x, int xc) { int len = p.length; int count = 0; while (u[0] == 0) { Nat.shiftDownWord(uLen, u, 0); count += 32; } { int zeroes = getTrailingZeroes(u[0]); if (zeroes > 0) { Nat.shiftDownBits(uLen, u, zeroes, 0); count += zeroes; } } for (int i = 0; i < count; ++i) { if ((x[0] & 1) != 0) { if (xc < 0) { xc += Nat.addTo(len, p, x); } else { xc += Nat.subFrom(len, p, x); } } // assert xc == 0 || xc == 1; Nat.shiftDownBit(len, x, xc); } return xc; } private static int getTrailingZeroes(int x) { // assert x != 0; int count = 0; while ((x & 1) == 0) { x >>>= 1; ++count; } return count; } }