blob: ead38c480961780e734cde6d20fd478831ed7953 [file] [log] [blame]
package org.bouncycastle.math.ec;
import org.bouncycastle.util.Arrays;
import java.math.BigInteger;
class IntArray
{
// TODO make m fixed for the IntArray, and hence compute T once and for all
private int[] m_ints;
public IntArray(int intLen)
{
m_ints = new int[intLen];
}
public IntArray(int[] ints)
{
m_ints = ints;
}
public IntArray(BigInteger bigInt)
{
this(bigInt, 0);
}
public IntArray(BigInteger bigInt, int minIntLen)
{
if (bigInt.signum() == -1)
{
throw new IllegalArgumentException("Only positive Integers allowed");
}
if (bigInt.equals(ECConstants.ZERO))
{
m_ints = new int[] { 0 };
return;
}
byte[] barr = bigInt.toByteArray();
int barrLen = barr.length;
int barrStart = 0;
if (barr[0] == 0)
{
// First byte is 0 to enforce highest (=sign) bit is zero.
// In this case ignore barr[0].
barrLen--;
barrStart = 1;
}
int intLen = (barrLen + 3) / 4;
if (intLen < minIntLen)
{
m_ints = new int[minIntLen];
}
else
{
m_ints = new int[intLen];
}
int iarrJ = intLen - 1;
int rem = barrLen % 4 + barrStart;
int temp = 0;
int barrI = barrStart;
if (barrStart < rem)
{
for (; barrI < rem; barrI++)
{
temp <<= 8;
int barrBarrI = barr[barrI];
if (barrBarrI < 0)
{
barrBarrI += 256;
}
temp |= barrBarrI;
}
m_ints[iarrJ--] = temp;
}
for (; iarrJ >= 0; iarrJ--)
{
temp = 0;
for (int i = 0; i < 4; i++)
{
temp <<= 8;
int barrBarrI = barr[barrI++];
if (barrBarrI < 0)
{
barrBarrI += 256;
}
temp |= barrBarrI;
}
m_ints[iarrJ] = temp;
}
}
public boolean isZero()
{
return m_ints.length == 0
|| (m_ints[0] == 0 && getUsedLength() == 0);
}
public int getUsedLength()
{
int highestIntPos = m_ints.length;
if (highestIntPos < 1)
{
return 0;
}
// Check if first element will act as sentinel
if (m_ints[0] != 0)
{
while (m_ints[--highestIntPos] == 0)
{
}
return highestIntPos + 1;
}
do
{
if (m_ints[--highestIntPos] != 0)
{
return highestIntPos + 1;
}
}
while (highestIntPos > 0);
return 0;
}
public int bitLength()
{
// JDK 1.5: see Integer.numberOfLeadingZeros()
int intLen = getUsedLength();
if (intLen == 0)
{
return 0;
}
int last = intLen - 1;
int highest = m_ints[last];
int bits = (last << 5) + 1;
// A couple of binary search steps
if ((highest & 0xffff0000) != 0)
{
if ((highest & 0xff000000) != 0)
{
bits += 24;
highest >>>= 24;
}
else
{
bits += 16;
highest >>>= 16;
}
}
else if (highest > 0x000000ff)
{
bits += 8;
highest >>>= 8;
}
while (highest != 1)
{
++bits;
highest >>>= 1;
}
return bits;
}
private int[] resizedInts(int newLen)
{
int[] newInts = new int[newLen];
int oldLen = m_ints.length;
int copyLen = oldLen < newLen ? oldLen : newLen;
System.arraycopy(m_ints, 0, newInts, 0, copyLen);
return newInts;
}
public BigInteger toBigInteger()
{
int usedLen = getUsedLength();
if (usedLen == 0)
{
return ECConstants.ZERO;
}
int highestInt = m_ints[usedLen - 1];
byte[] temp = new byte[4];
int barrI = 0;
boolean trailingZeroBytesDone = false;
for (int j = 3; j >= 0; j--)
{
byte thisByte = (byte) (highestInt >>> (8 * j));
if (trailingZeroBytesDone || (thisByte != 0))
{
trailingZeroBytesDone = true;
temp[barrI++] = thisByte;
}
}
int barrLen = 4 * (usedLen - 1) + barrI;
byte[] barr = new byte[barrLen];
for (int j = 0; j < barrI; j++)
{
barr[j] = temp[j];
}
// Highest value int is done now
for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--)
{
for (int j = 3; j >= 0; j--)
{
barr[barrI++] = (byte) (m_ints[iarrJ] >>> (8 * j));
}
}
return new BigInteger(1, barr);
}
public void shiftLeft()
{
int usedLen = getUsedLength();
if (usedLen == 0)
{
return;
}
if (m_ints[usedLen - 1] < 0)
{
// highest bit of highest used byte is set, so shifting left will
// make the IntArray one byte longer
usedLen++;
if (usedLen > m_ints.length)
{
// make the m_ints one byte longer, because we need one more
// byte which is not available in m_ints
m_ints = resizedInts(m_ints.length + 1);
}
}
boolean carry = false;
for (int i = 0; i < usedLen; i++)
{
// nextCarry is true if highest bit is set
boolean nextCarry = m_ints[i] < 0;
m_ints[i] <<= 1;
if (carry)
{
// set lowest bit
m_ints[i] |= 1;
}
carry = nextCarry;
}
}
public IntArray shiftLeft(int n)
{
int usedLen = getUsedLength();
if (usedLen == 0)
{
return this;
}
if (n == 0)
{
return this;
}
if (n > 31)
{
throw new IllegalArgumentException("shiftLeft() for max 31 bits "
+ ", " + n + "bit shift is not possible");
}
int[] newInts = new int[usedLen + 1];
int nm32 = 32 - n;
newInts[0] = m_ints[0] << n;
for (int i = 1; i < usedLen; i++)
{
newInts[i] = (m_ints[i] << n) | (m_ints[i - 1] >>> nm32);
}
newInts[usedLen] = m_ints[usedLen - 1] >>> nm32;
return new IntArray(newInts);
}
public void addShifted(IntArray other, int shift)
{
int usedLenOther = other.getUsedLength();
int newMinUsedLen = usedLenOther + shift;
if (newMinUsedLen > m_ints.length)
{
m_ints = resizedInts(newMinUsedLen);
//System.out.println("Resize required");
}
for (int i = 0; i < usedLenOther; i++)
{
m_ints[i + shift] ^= other.m_ints[i];
}
}
public int getLength()
{
return m_ints.length;
}
public boolean testBit(int n)
{
// theInt = n / 32
int theInt = n >> 5;
// theBit = n % 32
int theBit = n & 0x1F;
int tester = 1 << theBit;
return ((m_ints[theInt] & tester) != 0);
}
public void flipBit(int n)
{
// theInt = n / 32
int theInt = n >> 5;
// theBit = n % 32
int theBit = n & 0x1F;
int flipper = 1 << theBit;
m_ints[theInt] ^= flipper;
}
public void setBit(int n)
{
// theInt = n / 32
int theInt = n >> 5;
// theBit = n % 32
int theBit = n & 0x1F;
int setter = 1 << theBit;
m_ints[theInt] |= setter;
}
public IntArray multiply(IntArray other, int m)
{
// Lenght of c is 2m bits rounded up to the next int (32 bit)
int t = (m + 31) >> 5;
if (m_ints.length < t)
{
m_ints = resizedInts(t);
}
IntArray b = new IntArray(other.resizedInts(other.getLength() + 1));
IntArray c = new IntArray((m + m + 31) >> 5);
// IntArray c = new IntArray(t + t);
int testBit = 1;
for (int k = 0; k < 32; k++)
{
for (int j = 0; j < t; j++)
{
if ((m_ints[j] & testBit) != 0)
{
// The kth bit of m_ints[j] is set
c.addShifted(b, j);
}
}
testBit <<= 1;
b.shiftLeft();
}
return c;
}
// public IntArray multiplyLeftToRight(IntArray other, int m) {
// // Lenght of c is 2m bits rounded up to the next int (32 bit)
// int t = (m + 31) / 32;
// if (m_ints.length < t) {
// m_ints = resizedInts(t);
// }
//
// IntArray b = new IntArray(other.resizedInts(other.getLength() + 1));
// IntArray c = new IntArray((m + m + 31) / 32);
// // IntArray c = new IntArray(t + t);
// int testBit = 1 << 31;
// for (int k = 31; k >= 0; k--) {
// for (int j = 0; j < t; j++) {
// if ((m_ints[j] & testBit) != 0) {
// // The kth bit of m_ints[j] is set
// c.addShifted(b, j);
// }
// }
// testBit >>>= 1;
// if (k > 0) {
// c.shiftLeft();
// }
// }
// return c;
// }
// TODO note, redPol.length must be 3 for TPB and 5 for PPB
public void reduce(int m, int[] redPol)
{
for (int i = m + m - 2; i >= m; i--)
{
if (testBit(i))
{
int bit = i - m;
flipBit(bit);
flipBit(i);
int l = redPol.length;
while (--l >= 0)
{
flipBit(redPol[l] + bit);
}
}
}
m_ints = resizedInts((m + 31) >> 5);
}
public IntArray square(int m)
{
// TODO make the table static final
final int[] table = { 0x0, 0x1, 0x4, 0x5, 0x10, 0x11, 0x14, 0x15, 0x40,
0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55 };
int t = (m + 31) >> 5;
if (m_ints.length < t)
{
m_ints = resizedInts(t);
}
IntArray c = new IntArray(t + t);
// TODO twice the same code, put in separate private method
for (int i = 0; i < t; i++)
{
int v0 = 0;
for (int j = 0; j < 4; j++)
{
v0 = v0 >>> 8;
int u = (m_ints[i] >>> (j * 4)) & 0xF;
int w = table[u] << 24;
v0 |= w;
}
c.m_ints[i + i] = v0;
v0 = 0;
int upper = m_ints[i] >>> 16;
for (int j = 0; j < 4; j++)
{
v0 = v0 >>> 8;
int u = (upper >>> (j * 4)) & 0xF;
int w = table[u] << 24;
v0 |= w;
}
c.m_ints[i + i + 1] = v0;
}
return c;
}
public boolean equals(Object o)
{
if (!(o instanceof IntArray))
{
return false;
}
IntArray other = (IntArray) o;
int usedLen = getUsedLength();
if (other.getUsedLength() != usedLen)
{
return false;
}
for (int i = 0; i < usedLen; i++)
{
if (m_ints[i] != other.m_ints[i])
{
return false;
}
}
return true;
}
public int hashCode()
{
int usedLen = getUsedLength();
int hash = 1;
for (int i = 0; i < usedLen; i++)
{
hash = hash * 31 + m_ints[i];
}
return hash;
}
public Object clone()
{
return new IntArray(Arrays.clone(m_ints));
}
public String toString()
{
int usedLen = getUsedLength();
if (usedLen == 0)
{
return "0";
}
StringBuffer sb = new StringBuffer(Integer
.toBinaryString(m_ints[usedLen - 1]));
for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--)
{
String hexString = Integer.toBinaryString(m_ints[iarrJ]);
// Add leading zeroes, except for highest significant int
for (int i = hexString.length(); i < 8; i++)
{
hexString = "0" + hexString;
}
sb.append(hexString);
}
return sb.toString();
}
}