org.bouncycastle.pqc.legacy.math.linearalgebra.GF2nONBElement Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bcprov-ext-debug-jdk18on Show documentation
Show all versions of bcprov-ext-debug-jdk18on Show documentation
The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for Java 1.8 and later with debug enabled.
The newest version!
package org.bouncycastle.pqc.legacy.math.linearalgebra;
import java.math.BigInteger;
import java.security.SecureRandom;
import org.bouncycastle.util.Arrays;
/**
* This class implements an element of the finite field GF(2n ).
* It is represented in an optimal normal basis representation and holds the
* pointer mField to its corresponding field.
*
* @see GF2nField
* @see GF2nElement
*/
public class GF2nONBElement
extends GF2nElement
{
// /////////////////////////////////////////////////////////////////////
// member variables
// /////////////////////////////////////////////////////////////////////
private static final long[] mBitmask = new long[]{0x0000000000000001L,
0x0000000000000002L, 0x0000000000000004L, 0x0000000000000008L,
0x0000000000000010L, 0x0000000000000020L, 0x0000000000000040L,
0x0000000000000080L, 0x0000000000000100L, 0x0000000000000200L,
0x0000000000000400L, 0x0000000000000800L, 0x0000000000001000L,
0x0000000000002000L, 0x0000000000004000L, 0x0000000000008000L,
0x0000000000010000L, 0x0000000000020000L, 0x0000000000040000L,
0x0000000000080000L, 0x0000000000100000L, 0x0000000000200000L,
0x0000000000400000L, 0x0000000000800000L, 0x0000000001000000L,
0x0000000002000000L, 0x0000000004000000L, 0x0000000008000000L,
0x0000000010000000L, 0x0000000020000000L, 0x0000000040000000L,
0x0000000080000000L, 0x0000000100000000L, 0x0000000200000000L,
0x0000000400000000L, 0x0000000800000000L, 0x0000001000000000L,
0x0000002000000000L, 0x0000004000000000L, 0x0000008000000000L,
0x0000010000000000L, 0x0000020000000000L, 0x0000040000000000L,
0x0000080000000000L, 0x0000100000000000L, 0x0000200000000000L,
0x0000400000000000L, 0x0000800000000000L, 0x0001000000000000L,
0x0002000000000000L, 0x0004000000000000L, 0x0008000000000000L,
0x0010000000000000L, 0x0020000000000000L, 0x0040000000000000L,
0x0080000000000000L, 0x0100000000000000L, 0x0200000000000000L,
0x0400000000000000L, 0x0800000000000000L, 0x1000000000000000L,
0x2000000000000000L, 0x4000000000000000L, 0x8000000000000000L};
private static final long[] mMaxmask = new long[]{0x0000000000000001L,
0x0000000000000003L, 0x0000000000000007L, 0x000000000000000FL,
0x000000000000001FL, 0x000000000000003FL, 0x000000000000007FL,
0x00000000000000FFL, 0x00000000000001FFL, 0x00000000000003FFL,
0x00000000000007FFL, 0x0000000000000FFFL, 0x0000000000001FFFL,
0x0000000000003FFFL, 0x0000000000007FFFL, 0x000000000000FFFFL,
0x000000000001FFFFL, 0x000000000003FFFFL, 0x000000000007FFFFL,
0x00000000000FFFFFL, 0x00000000001FFFFFL, 0x00000000003FFFFFL,
0x00000000007FFFFFL, 0x0000000000FFFFFFL, 0x0000000001FFFFFFL,
0x0000000003FFFFFFL, 0x0000000007FFFFFFL, 0x000000000FFFFFFFL,
0x000000001FFFFFFFL, 0x000000003FFFFFFFL, 0x000000007FFFFFFFL,
0x00000000FFFFFFFFL, 0x00000001FFFFFFFFL, 0x00000003FFFFFFFFL,
0x00000007FFFFFFFFL, 0x0000000FFFFFFFFFL, 0x0000001FFFFFFFFFL,
0x0000003FFFFFFFFFL, 0x0000007FFFFFFFFFL, 0x000000FFFFFFFFFFL,
0x000001FFFFFFFFFFL, 0x000003FFFFFFFFFFL, 0x000007FFFFFFFFFFL,
0x00000FFFFFFFFFFFL, 0x00001FFFFFFFFFFFL, 0x00003FFFFFFFFFFFL,
0x00007FFFFFFFFFFFL, 0x0000FFFFFFFFFFFFL, 0x0001FFFFFFFFFFFFL,
0x0003FFFFFFFFFFFFL, 0x0007FFFFFFFFFFFFL, 0x000FFFFFFFFFFFFFL,
0x001FFFFFFFFFFFFFL, 0x003FFFFFFFFFFFFFL, 0x007FFFFFFFFFFFFFL,
0x00FFFFFFFFFFFFFFL, 0x01FFFFFFFFFFFFFFL, 0x03FFFFFFFFFFFFFFL,
0x07FFFFFFFFFFFFFFL, 0x0FFFFFFFFFFFFFFFL, 0x1FFFFFFFFFFFFFFFL,
0x3FFFFFFFFFFFFFFFL, 0x7FFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFFFL};
// mIBy64[j * 16 + i] = (j * 16 + i)/64
// i =
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
//
private static final int[] mIBY64 = new int[]{
// j =
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 8
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 9
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 10
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 11
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 12
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 13
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 14
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 15
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 16
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 17
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 18
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 19
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 20
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 21
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 22
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 // 23
};
private static final int MAXLONG = 64;
/**
* holds the length of the polynomial with 64 bit sized fields.
*/
private int mLength;
/**
* holds the value of mDeg % MAXLONG.
*/
private int mBit;
/**
* holds this element in ONB representation.
*/
private long[] mPol;
// /////////////////////////////////////////////////////////////////////
// constructors
// /////////////////////////////////////////////////////////////////////
/**
* Construct a random element over the field gf2n, using the
* specified source of randomness.
*
* @param gf2n the field
* @param rand the source of randomness
*/
public GF2nONBElement(GF2nONBField gf2n, SecureRandom rand)
{
mField = gf2n;
mDegree = mField.getDegree();
mLength = gf2n.getONBLength();
mBit = gf2n.getONBBit();
mPol = new long[mLength];
if (mLength > 1)
{
for (int j = 0; j < mLength - 1; j++)
{
mPol[j] = rand.nextLong();
}
long last = rand.nextLong();
mPol[mLength - 1] = last >>> (MAXLONG - mBit);
}
else
{
mPol[0] = rand.nextLong();
mPol[0] = mPol[0] >>> (MAXLONG - mBit);
}
}
/**
* Construct a new GF2nONBElement from its encoding.
*
* @param gf2n the field
* @param e the encoded element
*/
public GF2nONBElement(GF2nONBField gf2n, byte[] e)
{
mField = gf2n;
mDegree = mField.getDegree();
mLength = gf2n.getONBLength();
mBit = gf2n.getONBBit();
mPol = new long[mLength];
assign(e);
}
/**
* Construct the element of the field gf2n with the specified
* value val.
*
* @param gf2n the field
* @param val the value represented by a BigInteger
*/
public GF2nONBElement(GF2nONBField gf2n, BigInteger val)
{
mField = gf2n;
mDegree = mField.getDegree();
mLength = gf2n.getONBLength();
mBit = gf2n.getONBBit();
mPol = new long[mLength];
assign(val);
}
/**
* Construct the element of the field gf2n with the specified
* value val.
*
* @param gf2n the field
* @param val the value in ONB representation
*/
private GF2nONBElement(GF2nONBField gf2n, long[] val)
{
mField = gf2n;
mDegree = mField.getDegree();
mLength = gf2n.getONBLength();
mBit = gf2n.getONBBit();
mPol = val;
}
// /////////////////////////////////////////////////////////////////////
// pseudo-constructors
// /////////////////////////////////////////////////////////////////////
/**
* Copy constructor.
*
* @param gf2n the field
*/
public GF2nONBElement(GF2nONBElement gf2n)
{
mField = gf2n.mField;
mDegree = mField.getDegree();
mLength = ((GF2nONBField)mField).getONBLength();
mBit = ((GF2nONBField)mField).getONBBit();
mPol = new long[mLength];
assign(gf2n.getElement());
}
/**
* Create a new GF2nONBElement by cloning this GF2nPolynomialElement.
*
* @return a copy of this element
*/
public Object clone()
{
return new GF2nONBElement(this);
}
/**
* Create the zero element.
*
* @param gf2n the finite field
* @return the zero element in the given finite field
*/
public static GF2nONBElement ZERO(GF2nONBField gf2n)
{
long[] polynomial = new long[gf2n.getONBLength()];
return new GF2nONBElement(gf2n, polynomial);
}
/**
* Create the one element.
*
* @param gf2n the finite field
* @return the one element in the given finite field
*/
public static GF2nONBElement ONE(GF2nONBField gf2n)
{
int mLength = gf2n.getONBLength();
long[] polynomial = new long[mLength];
// fill mDegree coefficients with one's
for (int i = 0; i < mLength - 1; i++)
{
polynomial[i] = 0xffffffffffffffffL;
}
polynomial[mLength - 1] = mMaxmask[gf2n.getONBBit() - 1];
return new GF2nONBElement(gf2n, polynomial);
}
// /////////////////////////////////////////////////////////////////////
// assignments
// /////////////////////////////////////////////////////////////////////
/**
* assigns to this element the zero element
*/
void assignZero()
{
mPol = new long[mLength];
}
/**
* assigns to this element the one element
*/
void assignOne()
{
// fill mDegree coefficients with one's
for (int i = 0; i < mLength - 1; i++)
{
mPol[i] = 0xffffffffffffffffL;
}
mPol[mLength - 1] = mMaxmask[mBit - 1];
}
/**
* assigns to this element the value val.
*
* @param val the value represented by a BigInteger
*/
private void assign(BigInteger val)
{
assign(val.toByteArray());
}
/**
* assigns to this element the value val.
*
* @param val the value in ONB representation
*/
private void assign(long[] val)
{
System.arraycopy(val, 0, mPol, 0, mLength);
}
/**
* assigns to this element the value val. First: inverting the
* order of val into reversed[]. That means: reversed[0] = val[length - 1],
* ..., reversed[reversed.length - 1] = val[0]. Second: mPol[0] = sum{i = 0,
* ... 7} (val[i]<<(i*8)) .... mPol[1] = sum{i = 8, ... 15} (val[i]<<(i*8))
*
* @param val the value in ONB representation
*/
private void assign(byte[] val)
{
int j;
mPol = new long[mLength];
for (j = 0; j < val.length; j++)
{
mPol[j >>> 3] |= (val[val.length - 1 - j] & 0x00000000000000ffL) << ((j & 0x07) << 3);
}
}
// /////////////////////////////////////////////////////////////////
// comparison
// /////////////////////////////////////////////////////////////////
/**
* Checks whether this element is zero.
*
* @return true if this is the zero element
*/
public boolean isZero()
{
boolean result = true;
for (int i = 0; i < mLength && result; i++)
{
result = result && ((mPol[i] & 0xFFFFFFFFFFFFFFFFL) == 0);
}
return result;
}
/**
* Checks whether this element is one.
*
* @return true if this is the one element
*/
public boolean isOne()
{
boolean result = true;
for (int i = 0; i < mLength - 1 && result; i++)
{
result = result
&& ((mPol[i] & 0xFFFFFFFFFFFFFFFFL) == 0xFFFFFFFFFFFFFFFFL);
}
if (result)
{
result = result
&& ((mPol[mLength - 1] & mMaxmask[mBit - 1]) == mMaxmask[mBit - 1]);
}
return result;
}
/**
* Compare this element with another object.
*
* @param other the other object
* @return true if the two objects are equal, false
* otherwise
*/
public boolean equals(Object other)
{
if (other == null || !(other instanceof GF2nONBElement))
{
return false;
}
GF2nONBElement otherElem = (GF2nONBElement)other;
for (int i = 0; i < mLength; i++)
{
if (mPol[i] != otherElem.mPol[i])
{
return false;
}
}
return true;
}
/**
* @return the hash code of this element
*/
public int hashCode()
{
return Arrays.hashCode(mPol);
}
// /////////////////////////////////////////////////////////////////////
// access
// /////////////////////////////////////////////////////////////////////
/**
* Returns whether the highest bit of the bit representation is set
*
* @return true, if the highest bit of mPol is set, false, otherwise
*/
public boolean testRightmostBit()
{
// due to the reverse bit order (compared to 1363) this method returns
// the value of the leftmost bit
return (mPol[mLength - 1] & mBitmask[mBit - 1]) != 0L;
}
/**
* Checks whether the indexed bit of the bit representation is set. Warning:
* GF2nONBElement currently stores its bits in reverse order (compared to
* 1363) !!!
*
* @param index the index of the bit to test
* @return true if the indexed bit of mPol is set, false
* otherwise.
*/
boolean testBit(int index)
{
if (index < 0 || index > mDegree)
{
return false;
}
long test = mPol[index >>> 6] & mBitmask[index & 0x3f];
return test != 0x0L;
}
/**
* @return this element in its ONB representation
*/
private long[] getElement()
{
long[] result = new long[mPol.length];
System.arraycopy(mPol, 0, result, 0, mPol.length);
return result;
}
/**
* Returns the ONB representation of this element. The Bit-Order is
* exchanged (according to 1363)!
*
* @return this element in its representation and reverse bit-order
*/
private long[] getElementReverseOrder()
{
long[] result = new long[mPol.length];
for (int i = 0; i < mDegree; i++)
{
if (testBit(mDegree - i - 1))
{
result[i >>> 6] |= mBitmask[i & 0x3f];
}
}
return result;
}
/**
* Reverses the bit-order in this element(according to 1363). This is a
* hack!
*/
void reverseOrder()
{
mPol = getElementReverseOrder();
}
// /////////////////////////////////////////////////////////////////////
// arithmetic
// /////////////////////////////////////////////////////////////////////
/**
* Compute the sum of this element and addend.
*
* @param addend the addend
* @return this + other (newly created)
*/
public GFElement add(GFElement addend)
throws RuntimeException
{
GF2nONBElement result = new GF2nONBElement(this);
result.addToThis(addend);
return result;
}
/**
* Compute this + addend (overwrite this).
*
* @param addend the addend
*/
public void addToThis(GFElement addend)
throws RuntimeException
{
if (!(addend instanceof GF2nONBElement))
{
throw new RuntimeException();
}
if (!mField.equals(((GF2nONBElement)addend).mField))
{
throw new RuntimeException();
}
for (int i = 0; i < mLength; i++)
{
mPol[i] ^= ((GF2nONBElement)addend).mPol[i];
}
}
/**
* returns this element + 1.
*
* @return this + 1
*/
public GF2nElement increase()
{
GF2nONBElement result = new GF2nONBElement(this);
result.increaseThis();
return result;
}
/**
* increases this element.
*/
public void increaseThis()
{
addToThis(ONE((GF2nONBField)mField));
}
/**
* Compute the product of this element and factor.
*
* @param factor the factor
* @return this * factor (newly created)
*/
public GFElement multiply(GFElement factor)
throws RuntimeException
{
GF2nONBElement result = new GF2nONBElement(this);
result.multiplyThisBy(factor);
return result;
}
/**
* Compute this * factor (overwrite this).
*
* @param factor the factor
*/
public void multiplyThisBy(GFElement factor)
throws RuntimeException
{
if (!(factor instanceof GF2nONBElement))
{
throw new RuntimeException("The elements have different"
+ " representation: not yet" + " implemented");
}
if (!mField.equals(((GF2nONBElement)factor).mField))
{
throw new RuntimeException();
}
if (equals(factor))
{
squareThis();
}
else
{
long[] a = mPol;
long[] b = ((GF2nONBElement)factor).mPol;
long[] c = new long[mLength];
int[][] m = ((GF2nONBField)mField).mMult;
int degf, degb, s, fielda, fieldb, bita, bitb;
degf = mLength - 1;
degb = mBit - 1;
s = 0;
long TWOTOMAXLONGM1 = mBitmask[MAXLONG - 1];
long TWOTODEGB = mBitmask[degb];
boolean old, now;
// the product c of a and b (a*b = c) is calculated in mDegree
// cicles
// in every cicle one coefficient of c is calculated and stored
// k indicates the coefficient
//
for (int k = 0; k < mDegree; k++)
{
s = 0;
for (int i = 0; i < mDegree; i++)
{
// fielda = i / MAXLONG
//
fielda = mIBY64[i];
// bita = i % MAXLONG
//
bita = i & (MAXLONG - 1);
// fieldb = m[i][0] / MAXLONG
//
fieldb = mIBY64[m[i][0]];
// bitb = m[i][0] % MAXLONG
//
bitb = m[i][0] & (MAXLONG - 1);
if ((a[fielda] & mBitmask[bita]) != 0)
{
if ((b[fieldb] & mBitmask[bitb]) != 0)
{
s ^= 1;
}
if (m[i][1] != -1)
{
// fieldb = m[i][1] / MAXLONG
//
fieldb = mIBY64[m[i][1]];
// bitb = m[i][1] % MAXLONG
//
bitb = m[i][1] & (MAXLONG - 1);
if ((b[fieldb] & mBitmask[bitb]) != 0)
{
s ^= 1;
}
}
}
}
fielda = mIBY64[k];
bita = k & (MAXLONG - 1);
if (s != 0)
{
c[fielda] ^= mBitmask[bita];
}
// Circular shift of x and y one bit to the right,
// respectively.
if (mLength > 1)
{
// Shift x.
//
old = (a[degf] & 1) == 1;
for (int i = degf - 1; i >= 0; i--)
{
now = (a[i] & 1) != 0;
a[i] = a[i] >>> 1;
if (old)
{
a[i] ^= TWOTOMAXLONGM1;
}
old = now;
}
a[degf] = a[degf] >>> 1;
if (old)
{
a[degf] ^= TWOTODEGB;
}
// Shift y.
//
old = (b[degf] & 1) == 1;
for (int i = degf - 1; i >= 0; i--)
{
now = (b[i] & 1) != 0;
b[i] = b[i] >>> 1;
if (old)
{
b[i] ^= TWOTOMAXLONGM1;
}
old = now;
}
b[degf] = b[degf] >>> 1;
if (old)
{
b[degf] ^= TWOTODEGB;
}
}
else
{
old = (a[0] & 1) == 1;
a[0] = a[0] >>> 1;
if (old)
{
a[0] ^= TWOTODEGB;
}
old = (b[0] & 1) == 1;
b[0] = b[0] >>> 1;
if (old)
{
b[0] ^= TWOTODEGB;
}
}
}
assign(c);
}
}
/**
* returns this element to the power of 2.
*
* @return this2
*/
public GF2nElement square()
{
GF2nONBElement result = new GF2nONBElement(this);
result.squareThis();
return result;
}
/**
* squares this element.
*/
public void squareThis()
{
long[] pol = getElement();
int f = mLength - 1;
int b = mBit - 1;
// Shift the coefficients one bit to the left.
//
long TWOTOMAXLONGM1 = mBitmask[MAXLONG - 1];
boolean old, now;
old = (pol[f] & mBitmask[b]) != 0;
for (int i = 0; i < f; i++)
{
now = (pol[i] & TWOTOMAXLONGM1) != 0;
pol[i] = pol[i] << 1;
if (old)
{
pol[i] ^= 1;
}
old = now;
}
now = (pol[f] & mBitmask[b]) != 0;
pol[f] = pol[f] << 1;
if (old)
{
pol[f] ^= 1;
}
// Set the bit with index mDegree to zero.
//
if (now)
{
pol[f] ^= mBitmask[b + 1];
}
assign(pol);
}
/**
* Compute the multiplicative inverse of this element.
*
* @return this-1 (newly created)
* @throws ArithmeticException if this is the zero element.
*/
public GFElement invert()
throws ArithmeticException
{
GF2nONBElement result = new GF2nONBElement(this);
result.invertThis();
return result;
}
/**
* Multiplicatively invert of this element (overwrite this).
*
* @throws ArithmeticException if this is the zero element.
*/
public void invertThis()
throws ArithmeticException
{
if (isZero())
{
throw new ArithmeticException();
}
int r = 31; // mDegree kann nur 31 Bits lang sein!!!
// Bitlaenge von mDegree:
for (boolean found = false; !found && r >= 0; r--)
{
if (((mDegree - 1) & mBitmask[r]) != 0)
{
found = true;
}
}
r++;
GF2nElement m = ZERO((GF2nONBField)mField);
GF2nElement n = new GF2nONBElement(this);
int k = 1;
for (int i = r - 1; i >= 0; i--)
{
m = (GF2nElement)n.clone();
for (int j = 1; j <= k; j++)
{
m.squareThis();
}
n.multiplyThisBy(m);
k <<= 1;
if (((mDegree - 1) & mBitmask[i]) != 0)
{
n.squareThis();
n.multiplyThisBy(this);
k++;
}
}
n.squareThis();
}
/**
* returns the root ofthis element.
*
* @return this1/2
*/
public GF2nElement squareRoot()
{
GF2nONBElement result = new GF2nONBElement(this);
result.squareRootThis();
return result;
}
/**
* square roots this element.
*/
public void squareRootThis()
{
long[] pol = getElement();
int f = mLength - 1;
int b = mBit - 1;
// Shift the coefficients one bit to the right.
//
long TWOTOMAXLONGM1 = mBitmask[MAXLONG - 1];
boolean old, now;
old = (pol[0] & 1) != 0;
for (int i = f; i >= 0; i--)
{
now = (pol[i] & 1) != 0;
pol[i] = pol[i] >>> 1;
if (old)
{
if (i == f)
{
pol[i] ^= mBitmask[b];
}
else
{
pol[i] ^= TWOTOMAXLONGM1;
}
}
old = now;
}
assign(pol);
}
/**
* Returns the trace of this element.
*
* @return the trace of this element
*/
public int trace()
{
// trace = sum of coefficients
//
int result = 0;
int max = mLength - 1;
for (int i = 0; i < max; i++)
{
for (int j = 0; j < MAXLONG; j++)
{
if ((mPol[i] & mBitmask[j]) != 0)
{
result ^= 1;
}
}
}
int b = mBit;
for (int j = 0; j < b; j++)
{
if ((mPol[max] & mBitmask[j]) != 0)
{
result ^= 1;
}
}
return result;
}
/**
* Solves a quadratic equation.
* Let z2 + z = this. Then this method returns z.
*
* @return z with z2 + z = this
*/
public GF2nElement solveQuadraticEquation()
throws RuntimeException
{
if (trace() == 1)
{
throw new RuntimeException();
}
long TWOTOMAXLONGM1 = mBitmask[MAXLONG - 1];
long ZERO = 0L;
long ONE = 1L;
long[] p = new long[mLength];
long z = 0L;
int j = 1;
for (int i = 0; i < mLength - 1; i++)
{
for (j = 1; j < MAXLONG; j++)
{
//
if (!((((mBitmask[j] & mPol[i]) != ZERO) && ((z & mBitmask[j - 1]) != ZERO)) || (((mPol[i] & mBitmask[j]) == ZERO) && ((z & mBitmask[j - 1]) == ZERO))))
{
z ^= mBitmask[j];
}
}
p[i] = z;
if (((TWOTOMAXLONGM1 & z) != ZERO && (ONE & mPol[i + 1]) == ONE)
|| ((TWOTOMAXLONGM1 & z) == ZERO && (ONE & mPol[i + 1]) == ZERO))
{
z = ZERO;
}
else
{
z = ONE;
}
}
int b = mDegree & (MAXLONG - 1);
long LASTLONG = mPol[mLength - 1];
for (j = 1; j < b; j++)
{
if (!((((mBitmask[j] & LASTLONG) != ZERO) && ((mBitmask[j - 1] & z) != ZERO)) || (((mBitmask[j] & LASTLONG) == ZERO) && ((mBitmask[j - 1] & z) == ZERO))))
{
z ^= mBitmask[j];
}
}
p[mLength - 1] = z;
return new GF2nONBElement((GF2nONBField)mField, p);
}
// /////////////////////////////////////////////////////////////////
// conversion
// /////////////////////////////////////////////////////////////////
/**
* Returns a String representation of this element.
*
* @return String representation of this element with the specified radix
*/
public String toString()
{
return toString(16);
}
/**
* Returns a String representation of this element. radix
* specifies the radix of the String representation.
* NOTE: ONLY radix = 2 or radix = 16 IS IMPLEMENTED
*
* @param radix specifies the radix of the String representation
* @return String representation of this element with the specified radix
*/
public String toString(int radix)
{
String s = "";
long[] a = getElement();
int b = mBit;
if (radix == 2)
{
for (int j = b - 1; j >= 0; j--)
{
if ((a[a.length - 1] & ((long)1 << j)) == 0)
{
s += "0";
}
else
{
s += "1";
}
}
for (int i = a.length - 2; i >= 0; i--)
{
for (int j = MAXLONG - 1; j >= 0; j--)
{
if ((a[i] & mBitmask[j]) == 0)
{
s += "0";
}
else
{
s += "1";
}
}
}
}
else if (radix == 16)
{
final char[] HEX_CHARS = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
for (int i = a.length - 1; i >= 0; i--)
{
s += HEX_CHARS[(int)(a[i] >>> 60) & 0x0f];
s += HEX_CHARS[(int)(a[i] >>> 56) & 0x0f];
s += HEX_CHARS[(int)(a[i] >>> 52) & 0x0f];
s += HEX_CHARS[(int)(a[i] >>> 48) & 0x0f];
s += HEX_CHARS[(int)(a[i] >>> 44) & 0x0f];
s += HEX_CHARS[(int)(a[i] >>> 40) & 0x0f];
s += HEX_CHARS[(int)(a[i] >>> 36) & 0x0f];
s += HEX_CHARS[(int)(a[i] >>> 32) & 0x0f];
s += HEX_CHARS[(int)(a[i] >>> 28) & 0x0f];
s += HEX_CHARS[(int)(a[i] >>> 24) & 0x0f];
s += HEX_CHARS[(int)(a[i] >>> 20) & 0x0f];
s += HEX_CHARS[(int)(a[i] >>> 16) & 0x0f];
s += HEX_CHARS[(int)(a[i] >>> 12) & 0x0f];
s += HEX_CHARS[(int)(a[i] >>> 8) & 0x0f];
s += HEX_CHARS[(int)(a[i] >>> 4) & 0x0f];
s += HEX_CHARS[(int)(a[i]) & 0x0f];
s += " ";
}
}
return s;
}
/**
* Returns this element as FlexiBigInt. The conversion is P1363-conform.
*
* @return this element as BigInteger
*/
public BigInteger toFlexiBigInt()
{
/** @todo this method does not reverse the bit-order as it should!!! */
return new BigInteger(1, toByteArray());
}
/**
* Returns this element as byte array. The conversion is P1363-conform.
*
* @return this element as byte array
*/
public byte[] toByteArray()
{
/** @todo this method does not reverse the bit-order as it should!!! */
int k = ((mDegree - 1) >> 3) + 1;
byte[] result = new byte[k];
int i;
for (i = 0; i < k; i++)
{
result[k - i - 1] = (byte)((mPol[i >>> 3] & (0x00000000000000ffL << ((i & 0x07) << 3))) >>> ((i & 0x07) << 3));
}
return result;
}
}