package org.bouncycastle.math.raw;
public abstract class Mont256
{
private static final long M = 0xFFFFFFFFL;
public static int inverse32(int x)
{
// assert (x & 1) == 1;
int z = x; // x.z == 1 mod 2**3
z *= 2 - x * z; // x.z == 1 mod 2**6
z *= 2 - x * z; // x.z == 1 mod 2**12
z *= 2 - x * z; // x.z == 1 mod 2**24
z *= 2 - x * z; // x.z == 1 mod 2**48
// assert x * z == 1;
return z;
}
public static void multAdd(int[] x, int[] y, int[] z, int[] m, int mInv32)
{
int z_8 = 0;
long y_0 = y[0] & M;
for (int i = 0; i < 8; ++i)
{
long z_0 = z[0] & M;
long x_i = x[i] & M;
long prod1 = x_i * y_0;
long carry = (prod1 & M) + z_0;
long t = ((int)carry * mInv32) & M;
long prod2 = t * (m[0] & M);
carry += (prod2 & M);
// assert (int)carry == 0;
carry = (carry >>> 32) + (prod1 >>> 32) + (prod2 >>> 32);
for (int j = 1; j < 8; ++j)
{
prod1 = x_i * (y[j] & M);
prod2 = t * (m[j] & M);
carry += (prod1 & M) + (prod2 & M) + (z[j] & M);
z[j - 1] = (int)carry;
carry = (carry >>> 32) + (prod1 >>> 32) + (prod2 >>> 32);
}
carry += (z_8 & M);
z[7] = (int)carry;
z_8 = (int)(carry >>> 32);
}
if (z_8 != 0 || Nat256.gte(z, m))
{
Nat256.sub(z, m, z);
}
}
public static void multAddXF(int[] x, int[] y, int[] z, int[] m)
{
// assert m[0] == M;
int z_8 = 0;
long y_0 = y[0] & M;
for (int i = 0; i < 8; ++i)
{
long x_i = x[i] & M;
long carry = x_i * y_0 + (z[0] & M);
long t = carry & M;
carry = (carry >>> 32) + t;
for (int j = 1; j < 8; ++j)
{
long prod1 = x_i * (y[j] & M);
long prod2 = t * (m[j] & M);
carry += (prod1 & M) + (prod2 & M) + (z[j] & M);
z[j - 1] = (int)carry;
carry = (carry >>> 32) + (prod1 >>> 32) + (prod2 >>> 32);
}
carry += (z_8 & M);
z[7] = (int)carry;
z_8 = (int)(carry >>> 32);
}
if (z_8 != 0 || Nat256.gte(z, m))
{
Nat256.sub(z, m, z);
}
}
public static void reduce(int[] z, int[] m, int mInv32)
{
for (int i = 0; i < 8; ++i)
{
int z_0 = z[0];
long t = (z_0 * mInv32) & M;
long carry = t * (m[0] & M) + (z_0 & M);
// assert (int)carry == 0;
carry >>>= 32;
for (int j = 1; j < 8; ++j)
{
carry += t * (m[j] & M) + (z[j] & M);
z[j - 1] = (int)carry;
carry >>>= 32;
}
z[7] = (int)carry;
// assert carry >>> 32 == 0;
}
if (Nat256.gte(z, m))
{
Nat256.sub(z, m, z);
}
}
public static void reduceXF(int[] z, int[] m)
{
// assert m[0] == M;
for (int i = 0; i < 8; ++i)
{
int z_0 = z[0];
long t = z_0 & M;
long carry = t;
for (int j = 1; j < 8; ++j)
{
carry += t * (m[j] & M) + (z[j] & M);
z[j - 1] = (int)carry;
carry >>>= 32;
}
z[7] = (int)carry;
// assert carry >>> 32 == 0;
}
if (Nat256.gte(z, m))
{
Nat256.sub(z, m, z);
}
}
}