package org.bouncycastle.math.raw; import java.math.BigInteger; import org.bouncycastle.util.Pack; public abstract class Nat { private static final long M = 0xFFFFFFFFL; public static int add(int len, int[] x, int[] y, int[] z) { long c = 0; for (int i = 0; i < len; ++i) { c += (x[i] & M) + (y[i] & M); z[i] = (int)c; c >>>= 32; } return (int)c; } public static int add33At(int len, int x, int[] z, int zPos) { // assert zPos <= (len - 2); long c = (z[zPos + 0] & M) + (x & M); z[zPos + 0] = (int)c; c >>>= 32; c += (z[zPos + 1] & M) + 1L; z[zPos + 1] = (int)c; c >>>= 32; return c == 0 ? 0 : incAt(len, z, zPos + 2); } public static int add33At(int len, int x, int[] z, int zOff, int zPos) { // assert zPos <= (len - 2); long c = (z[zOff + zPos] & M) + (x & M); z[zOff + zPos] = (int)c; c >>>= 32; c += (z[zOff + zPos + 1] & M) + 1L; z[zOff + zPos + 1] = (int)c; c >>>= 32; return c == 0 ? 0 : incAt(len, z, zOff, zPos + 2); } public static int add33To(int len, int x, int[] z) { long c = (z[0] & M) + (x & M); z[0] = (int)c; c >>>= 32; c += (z[1] & M) + 1L; z[1] = (int)c; c >>>= 32; return c == 0 ? 0 : incAt(len, z, 2); } public static int add33To(int len, int x, int[] z, int zOff) { long c = (z[zOff + 0] & M) + (x & M); z[zOff + 0] = (int)c; c >>>= 32; c += (z[zOff + 1] & M) + 1L; z[zOff + 1] = (int)c; c >>>= 32; return c == 0 ? 0 : incAt(len, z, zOff, 2); } public static int addBothTo(int len, int[] x, int[] y, int[] z) { long c = 0; for (int i = 0; i < len; ++i) { c += (x[i] & M) + (y[i] & M) + (z[i] & M); z[i] = (int)c; c >>>= 32; } return (int)c; } public static int addBothTo(int len, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) { long c = 0; for (int i = 0; i < len; ++i) { c += (x[xOff + i] & M) + (y[yOff + i] & M) + (z[zOff + i] & M); z[zOff + i] = (int)c; c >>>= 32; } return (int)c; } public static int addDWordAt(int len, long x, int[] z, int zPos) { // assert zPos <= (len - 2); long c = (z[zPos + 0] & M) + (x & M); z[zPos + 0] = (int)c; c >>>= 32; c += (z[zPos + 1] & M) + (x >>> 32); z[zPos + 1] = (int)c; c >>>= 32; return c == 0 ? 0 : incAt(len, z, zPos + 2); } public static int addDWordAt(int len, long x, int[] z, int zOff, int zPos) { // assert zPos <= (len - 2); long c = (z[zOff + zPos] & M) + (x & M); z[zOff + zPos] = (int)c; c >>>= 32; c += (z[zOff + zPos + 1] & M) + (x >>> 32); z[zOff + zPos + 1] = (int)c; c >>>= 32; return c == 0 ? 0 : incAt(len, z, zOff, zPos + 2); } public static int addDWordTo(int len, long x, int[] z) { long c = (z[0] & M) + (x & M); z[0] = (int)c; c >>>= 32; c += (z[1] & M) + (x >>> 32); z[1] = (int)c; c >>>= 32; return c == 0 ? 0 : incAt(len, z, 2); } public static int addDWordTo(int len, long x, int[] z, int zOff) { long c = (z[zOff + 0] & M) + (x & M); z[zOff + 0] = (int)c; c >>>= 32; c += (z[zOff + 1] & M) + (x >>> 32); z[zOff + 1] = (int)c; c >>>= 32; return c == 0 ? 0 : incAt(len, z, zOff, 2); } public static int addTo(int len, int[] x, int[] z) { long c = 0; for (int i = 0; i < len; ++i) { c += (x[i] & M) + (z[i] & M); z[i] = (int)c; c >>>= 32; } return (int)c; } public static int addTo(int len, int[] x, int xOff, int[] z, int zOff) { long c = 0; for (int i = 0; i < len; ++i) { c += (x[xOff + i] & M) + (z[zOff + i] & M); z[zOff + i] = (int)c; c >>>= 32; } return (int)c; } public static int addWordAt(int len, int x, int[] z, int zPos) { // assert zPos <= (len - 1); long c = (x & M) + (z[zPos] & M); z[zPos] = (int)c; c >>>= 32; return c == 0 ? 0 : incAt(len, z, zPos + 1); } public static int addWordAt(int len, int x, int[] z, int zOff, int zPos) { // assert zPos <= (len - 1); long c = (x & M) + (z[zOff + zPos] & M); z[zOff + zPos] = (int)c; c >>>= 32; return c == 0 ? 0 : incAt(len, z, zOff, zPos + 1); } public static int addWordTo(int len, int x, int[] z) { long c = (x & M) + (z[0] & M); z[0] = (int)c; c >>>= 32; return c == 0 ? 0 : incAt(len, z, 1); } public static int addWordTo(int len, int x, int[] z, int zOff) { long c = (x & M) + (z[zOff] & M); z[zOff] = (int)c; c >>>= 32; return c == 0 ? 0 : incAt(len, z, zOff, 1); } public static int[] copy(int len, int[] x) { int[] z = new int[len]; System.arraycopy(x, 0, z, 0, len); return z; } public static void copy(int len, int[] x, int[] z) { System.arraycopy(x, 0, z, 0, len); } public static int[] create(int len) { return new int[len]; } public static long[] create64(int len) { return new long[len]; } public static int dec(int len, int[] z) { for (int i = 0; i < len; ++i) { if (--z[i] != -1) { return 0; } } return -1; } public static int dec(int len, int[] x, int[] z) { int i = 0; while (i < len) { int c = x[i] - 1; z[i] = c; ++i; if (c != -1) { while (i < len) { z[i] = x[i]; ++i; } return 0; } } return -1; } public static int decAt(int len, int[] z, int zPos) { // assert zPos <= len; for (int i = zPos; i < len; ++i) { if (--z[i] != -1) { return 0; } } return -1; } public static int decAt(int len, int[] z, int zOff, int zPos) { // assert zPos <= len; for (int i = zPos; i < len; ++i) { if (--z[zOff + i] != -1) { return 0; } } return -1; } public static boolean eq(int len, int[] x, int[] y) { for (int i = len - 1; i >= 0; --i) { if (x[i] != y[i]) { return false; } } return true; } public static int[] fromBigInteger(int bits, BigInteger x) { if (x.signum() < 0 || x.bitLength() > bits) { throw new IllegalArgumentException(); } int len = (bits + 31) >> 5; int[] z = create(len); int i = 0; while (x.signum() != 0) { z[i++] = x.intValue(); x = x.shiftRight(32); } return z; } public static int getBit(int[] x, int bit) { if (bit == 0) { return x[0] & 1; } int w = bit >> 5; if (w < 0 || w >= x.length) { return 0; } int b = bit & 31; return (x[w] >>> b) & 1; } public static boolean gte(int len, int[] x, int[] y) { for (int i = len - 1; i >= 0; --i) { int x_i = x[i] ^ Integer.MIN_VALUE; int y_i = y[i] ^ Integer.MIN_VALUE; if (x_i < y_i) return false; if (x_i > y_i) return true; } return true; } public static int inc(int len, int[] z) { for (int i = 0; i < len; ++i) { if (++z[i] != 0) { return 0; } } return 1; } public static int inc(int len, int[] x, int[] z) { int i = 0; while (i < len) { int c = x[i] + 1; z[i] = c; ++i; if (c != 0) { while (i < len) { z[i] = x[i]; ++i; } return 0; } } return 1; } public static int incAt(int len, int[] z, int zPos) { // assert zPos <= len; for (int i = zPos; i < len; ++i) { if (++z[i] != 0) { return 0; } } return 1; } public static int incAt(int len, int[] z, int zOff, int zPos) { // assert zPos <= len; for (int i = zPos; i < len; ++i) { if (++z[zOff + i] != 0) { return 0; } } return 1; } public static boolean isOne(int len, int[] x) { if (x[0] != 1) { return false; } for (int i = 1; i < len; ++i) { if (x[i] != 0) { return false; } } return true; } public static boolean isZero(int len, int[] x) { for (int i = 0; i < len; ++i) { if (x[i] != 0) { return false; } } return true; } public static void mul(int len, int[] x, int[] y, int[] zz) { zz[len] = mulWord(len, x[0], y, zz); for (int i = 1; i < len; ++i) { zz[i + len] = mulWordAddTo(len, x[i], y, 0, zz, i); } } public static void mul(int len, int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff) { zz[zzOff + len] = mulWord(len, x[xOff], y, yOff, zz, zzOff); for (int i = 1; i < len; ++i) { zz[zzOff + i + len] = mulWordAddTo(len, x[xOff + i], y, yOff, zz, zzOff + i); } } public static int mulAddTo(int len, int[] x, int[] y, int[] zz) { long zc = 0; for (int i = 0; i < len; ++i) { long c = mulWordAddTo(len, x[i], y, 0, zz, i) & M; c += zc + (zz[i + len] & M); zz[i + len] = (int)c; zc = c >>> 32; } return (int)zc; } public static int mulAddTo(int len, int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff) { long zc = 0; for (int i = 0; i < len; ++i) { long c = mulWordAddTo(len, x[xOff + i], y, yOff, zz, zzOff) & M; c += zc + (zz[zzOff + len] & M); zz[zzOff + len] = (int)c; zc = c >>> 32; ++zzOff; } return (int)zc; } public static int mul31BothAdd(int len, int a, int[] x, int b, int[] y, int[] z, int zOff) { long c = 0, aVal = a & M, bVal = b & M; int i = 0; do { c += aVal * (x[i] & M) + bVal * (y[i] & M) + (z[zOff + i] & M); z[zOff + i] = (int)c; c >>>= 32; } while (++i < len); return (int)c; } public static int mulWord(int len, int x, int[] y, int[] z) { long c = 0, xVal = x & M; int i = 0; do { c += xVal * (y[i] & M); z[i] = (int)c; c >>>= 32; } while (++i < len); return (int)c; } public static int mulWord(int len, int x, int[] y, int yOff, int[] z, int zOff) { long c = 0, xVal = x & M; int i = 0; do { c += xVal * (y[yOff + i] & M); z[zOff + i] = (int)c; c >>>= 32; } while (++i < len); return (int)c; } public static int mulWordAddTo(int len, int x, int[] y, int yOff, int[] z, int zOff) { long c = 0, xVal = x & M; int i = 0; do { c += xVal * (y[yOff + i] & M) + (z[zOff + i] & M); z[zOff + i] = (int)c; c >>>= 32; } while (++i < len); return (int)c; } public static int mulWordDwordAddAt(int len, int x, long y, int[] z, int zPos) { // assert zPos <= (len - 3); long c = 0, xVal = x & M; c += xVal * (y & M) + (z[zPos + 0] & M); z[zPos + 0] = (int)c; c >>>= 32; c += xVal * (y >>> 32) + (z[zPos + 1] & M); z[zPos + 1] = (int)c; c >>>= 32; c += (z[zPos + 2] & M); z[zPos + 2] = (int)c; c >>>= 32; return c == 0 ? 0 : incAt(len, z, zPos + 3); } public static int shiftDownBit(int len, int[] z, int c) { int i = len; while (--i >= 0) { int next = z[i]; z[i] = (next >>> 1) | (c << 31); c = next; } return c << 31; } public static int shiftDownBit(int len, int[] z, int zOff, int c) { int i = len; while (--i >= 0) { int next = z[zOff + i]; z[zOff + i] = (next >>> 1) | (c << 31); c = next; } return c << 31; } public static int shiftDownBit(int len, int[] x, int c, int[] z) { int i = len; while (--i >= 0) { int next = x[i]; z[i] = (next >>> 1) | (c << 31); c = next; } return c << 31; } public static int shiftDownBit(int len, int[] x, int xOff, int c, int[] z, int zOff) { int i = len; while (--i >= 0) { int next = x[xOff + i]; z[zOff + i] = (next >>> 1) | (c << 31); c = next; } return c << 31; } public static int shiftDownBits(int len, int[] z, int bits, int c) { // assert bits > 0 && bits < 32; int i = len; while (--i >= 0) { int next = z[i]; z[i] = (next >>> bits) | (c << -bits); c = next; } return c << -bits; } public static int shiftDownBits(int len, int[] z, int zOff, int bits, int c) { // assert bits > 0 && bits < 32; int i = len; while (--i >= 0) { int next = z[zOff + i]; z[zOff + i] = (next >>> bits) | (c << -bits); c = next; } return c << -bits; } public static int shiftDownBits(int len, int[] x, int bits, int c, int[] z) { // assert bits > 0 && bits < 32; int i = len; while (--i >= 0) { int next = x[i]; z[i] = (next >>> bits) | (c << -bits); c = next; } return c << -bits; } public static int shiftDownBits(int len, int[] x, int xOff, int bits, int c, int[] z, int zOff) { // assert bits > 0 && bits < 32; int i = len; while (--i >= 0) { int next = x[xOff + i]; z[zOff + i] = (next >>> bits) | (c << -bits); c = next; } return c << -bits; } public static int shiftDownWord(int len, int[] z, int c) { int i = len; while (--i >= 0) { int next = z[i]; z[i] = c; c = next; } return c; } public static int shiftUpBit(int len, int[] z, int c) { for (int i = 0; i < len; ++i) { int next = z[i]; z[i] = (next << 1) | (c >>> 31); c = next; } return c >>> 31; } public static int shiftUpBit(int len, int[] z, int zOff, int c) { for (int i = 0; i < len; ++i) { int next = z[zOff + i]; z[zOff + i] = (next << 1) | (c >>> 31); c = next; } return c >>> 31; } public static int shiftUpBit(int len, int[] x, int c, int[] z) { for (int i = 0; i < len; ++i) { int next = x[i]; z[i] = (next << 1) | (c >>> 31); c = next; } return c >>> 31; } public static int shiftUpBit(int len, int[] x, int xOff, int c, int[] z, int zOff) { for (int i = 0; i < len; ++i) { int next = x[xOff + i]; z[zOff + i] = (next << 1) | (c >>> 31); c = next; } return c >>> 31; } public static long shiftUpBit64(int len, long[] x, int xOff, long c, long[] z, int zOff) { for (int i = 0; i < len; ++i) { long next = x[xOff + i]; z[zOff + i] = (next << 1) | (c >>> 63); c = next; } return c >>> 63; } public static int shiftUpBits(int len, int[] z, int bits, int c) { // assert bits > 0 && bits < 32; for (int i = 0; i < len; ++i) { int next = z[i]; z[i] = (next << bits) | (c >>> -bits); c = next; } return c >>> -bits; } public static int shiftUpBits(int len, int[] z, int zOff, int bits, int c) { // assert bits > 0 && bits < 32; for (int i = 0; i < len; ++i) { int next = z[zOff + i]; z[zOff + i] = (next << bits) | (c >>> -bits); c = next; } return c >>> -bits; } public static long shiftUpBits64(int len, long[] z, int zOff, int bits, long c) { // assert bits > 0 && bits < 64; for (int i = 0; i < len; ++i) { long next = z[zOff + i]; z[zOff + i] = (next << bits) | (c >>> -bits); c = next; } return c >>> -bits; } public static int shiftUpBits(int len, int[] x, int bits, int c, int[] z) { // assert bits > 0 && bits < 32; for (int i = 0; i < len; ++i) { int next = x[i]; z[i] = (next << bits) | (c >>> -bits); c = next; } return c >>> -bits; } public static int shiftUpBits(int len, int[] x, int xOff, int bits, int c, int[] z, int zOff) { // assert bits > 0 && bits < 32; for (int i = 0; i < len; ++i) { int next = x[xOff + i]; z[zOff + i] = (next << bits) | (c >>> -bits); c = next; } return c >>> -bits; } public static long shiftUpBits64(int len, long[] x, int xOff, int bits, long c, long[] z, int zOff) { // assert bits > 0 && bits < 64; for (int i = 0; i < len; ++i) { long next = x[xOff + i]; z[zOff + i] = (next << bits) | (c >>> -bits); c = next; } return c >>> -bits; } public static void square(int len, int[] x, int[] zz) { int extLen = len << 1; int c = 0; int j = len, k = extLen; do { long xVal = (x[--j] & M); long p = xVal * xVal; zz[--k] = (c << 31) | (int)(p >>> 33); zz[--k] = (int)(p >>> 1); c = (int)p; } while (j > 0); for (int i = 1; i < len; ++i) { c = squareWordAdd(x, i, zz); addWordAt(extLen, c, zz, i << 1); } shiftUpBit(extLen, zz, x[0] << 31); } public static void square(int len, int[] x, int xOff, int[] zz, int zzOff) { int extLen = len << 1; int c = 0; int j = len, k = extLen; do { long xVal = (x[xOff + --j] & M); long p = xVal * xVal; zz[zzOff + --k] = (c << 31) | (int)(p >>> 33); zz[zzOff + --k] = (int)(p >>> 1); c = (int)p; } while (j > 0); for (int i = 1; i < len; ++i) { c = squareWordAdd(x, xOff, i, zz, zzOff); addWordAt(extLen, c, zz, zzOff, i << 1); } shiftUpBit(extLen, zz, zzOff, x[xOff] << 31); } public static int squareWordAdd(int[] x, int xPos, int[] z) { long c = 0, xVal = x[xPos] & M; int i = 0; do { c += xVal * (x[i] & M) + (z[xPos + i] & M); z[xPos + i] = (int)c; c >>>= 32; } while (++i < xPos); return (int)c; } public static int squareWordAdd(int[] x, int xOff, int xPos, int[] z, int zOff) { long c = 0, xVal = x[xOff + xPos] & M; int i = 0; do { c += xVal * (x[xOff + i] & M) + (z[xPos + zOff] & M); z[xPos + zOff] = (int)c; c >>>= 32; ++zOff; } while (++i < xPos); return (int)c; } public static int sub(int len, int[] x, int[] y, int[] z) { long c = 0; for (int i = 0; i < len; ++i) { c += (x[i] & M) - (y[i] & M); z[i] = (int)c; c >>= 32; } return (int)c; } public static int sub(int len, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) { long c = 0; for (int i = 0; i < len; ++i) { c += (x[xOff + i] & M) - (y[yOff + i] & M); z[zOff + i] = (int)c; c >>= 32; } return (int)c; } public static int sub33At(int len, int x, int[] z, int zPos) { // assert zPos <= (len - 2); long c = (z[zPos + 0] & M) - (x & M); z[zPos + 0] = (int)c; c >>= 32; c += (z[zPos + 1] & M) - 1; z[zPos + 1] = (int)c; c >>= 32; return c == 0 ? 0 : decAt(len, z, zPos + 2); } public static int sub33At(int len, int x, int[] z, int zOff, int zPos) { // assert zPos <= (len - 2); long c = (z[zOff + zPos] & M) - (x & M); z[zOff + zPos] = (int)c; c >>= 32; c += (z[zOff + zPos + 1] & M) - 1; z[zOff + zPos + 1] = (int)c; c >>= 32; return c == 0 ? 0 : decAt(len, z, zOff, zPos + 2); } public static int sub33From(int len, int x, int[] z) { long c = (z[0] & M) - (x & M); z[0] = (int)c; c >>= 32; c += (z[1] & M) - 1; z[1] = (int)c; c >>= 32; return c == 0 ? 0 : decAt(len, z, 2); } public static int sub33From(int len, int x, int[] z, int zOff) { long c = (z[zOff + 0] & M) - (x & M); z[zOff + 0] = (int)c; c >>= 32; c += (z[zOff + 1] & M) - 1; z[zOff + 1] = (int)c; c >>= 32; return c == 0 ? 0 : decAt(len, z, zOff, 2); } public static int subBothFrom(int len, int[] x, int[] y, int[] z) { long c = 0; for (int i = 0; i < len; ++i) { c += (z[i] & M) - (x[i] & M) - (y[i] & M); z[i] = (int)c; c >>= 32; } return (int)c; } public static int subBothFrom(int len, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) { long c = 0; for (int i = 0; i < len; ++i) { c += (z[zOff + i] & M) - (x[xOff + i] & M) - (y[yOff + i] & M); z[zOff + i] = (int)c; c >>= 32; } return (int)c; } public static int subDWordAt(int len, long x, int[] z, int zPos) { // assert zPos <= (len - 2); long c = (z[zPos + 0] & M) - (x & M); z[zPos + 0] = (int)c; c >>= 32; c += (z[zPos + 1] & M) - (x >>> 32); z[zPos + 1] = (int)c; c >>= 32; return c == 0 ? 0 : decAt(len, z, zPos + 2); } public static int subDWordAt(int len, long x, int[] z, int zOff, int zPos) { // assert zPos <= (len - 2); long c = (z[zOff + zPos] & M) - (x & M); z[zOff + zPos] = (int)c; c >>= 32; c += (z[zOff + zPos + 1] & M) - (x >>> 32); z[zOff + zPos + 1] = (int)c; c >>= 32; return c == 0 ? 0 : decAt(len, z, zOff, zPos + 2); } public static int subDWordFrom(int len, long x, int[] z) { long c = (z[0] & M) - (x & M); z[0] = (int)c; c >>= 32; c += (z[1] & M) - (x >>> 32); z[1] = (int)c; c >>= 32; return c == 0 ? 0 : decAt(len, z, 2); } public static int subDWordFrom(int len, long x, int[] z, int zOff) { long c = (z[zOff + 0] & M) - (x & M); z[zOff + 0] = (int)c; c >>= 32; c += (z[zOff + 1] & M) - (x >>> 32); z[zOff + 1] = (int)c; c >>= 32; return c == 0 ? 0 : decAt(len, z, zOff, 2); } public static int subFrom(int len, int[] x, int[] z) { long c = 0; for (int i = 0; i < len; ++i) { c += (z[i] & M) - (x[i] & M); z[i] = (int)c; c >>= 32; } return (int)c; } public static int subFrom(int len, int[] x, int xOff, int[] z, int zOff) { long c = 0; for (int i = 0; i < len; ++i) { c += (z[zOff + i] & M) - (x[xOff + i] & M); z[zOff + i] = (int)c; c >>= 32; } return (int)c; } public static int subWordAt(int len, int x, int[] z, int zPos) { // assert zPos <= (len - 1); long c = (z[zPos] & M) - (x & M); z[zPos] = (int)c; c >>= 32; return c == 0 ? 0 : decAt(len, z, zPos + 1); } public static int subWordAt(int len, int x, int[] z, int zOff, int zPos) { // assert zPos <= (len - 1); long c = (z[zOff + zPos] & M) - (x & M); z[zOff + zPos] = (int)c; c >>= 32; return c == 0 ? 0 : decAt(len, z, zOff, zPos + 1); } public static int subWordFrom(int len, int x, int[] z) { long c = (z[0] & M) - (x & M); z[0] = (int)c; c >>= 32; return c == 0 ? 0 : decAt(len, z, 1); } public static int subWordFrom(int len, int x, int[] z, int zOff) { long c = (z[zOff + 0] & M) - (x & M); z[zOff + 0] = (int)c; c >>= 32; return c == 0 ? 0 : decAt(len, z, zOff, 1); } public static BigInteger toBigInteger(int len, int[] x) { byte[] bs = new byte[len << 2]; for (int i = 0; i < len; ++i) { int x_i = x[i]; if (x_i != 0) { Pack.intToBigEndian(x_i, bs, (len - 1 - i) << 2); } } return new BigInteger(1, bs); } public static void zero(int len, int[] z) { for (int i = 0; i < len; ++i) { z[i] = 0; } } public static void zero64(int len, long[] z) { for (int i = 0; i < len; ++i) { z[i] = 0L; } } }