package org.bouncycastle.pqc.math.linearalgebra;


import java.math.BigInteger;
import java.util.Random;

import org.bouncycastle.util.Arrays;


This class stores very long strings of bits and does some basic arithmetics. It is used by GF2nField, GF2nPolynomialField and GFnPolynomialElement.
See Also:
/** * This class stores very long strings of bits and does some basic arithmetics. * It is used by <tt>GF2nField</tt>, <tt>GF2nPolynomialField</tt> and * <tt>GFnPolynomialElement</tt>. * * @see GF2nPolynomialElement * @see GF2nField */
public class GF2Polynomial { // number of bits stored in this GF2Polynomial private int len; // number of int used in value private int blocks; // storage private int[] value; // Random source private static Random rand = new Random(); // Lookup-Table for vectorMult: parity[a]= #1(a) mod 2 == 1 private static final boolean[] parity = {false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false}; // Lookup-Table for Squaring: squaringTable[a]=a^2 private static final short[] squaringTable = {0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015, 0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055, 0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115, 0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155, 0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415, 0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455, 0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515, 0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555, 0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015, 0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055, 0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115, 0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155, 0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415, 0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455, 0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515, 0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555, 0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015, 0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055, 0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115, 0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155, 0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415, 0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455, 0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515, 0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555, 0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015, 0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055, 0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115, 0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155, 0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415, 0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455, 0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515, 0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555}; // pre-computed Bitmask for fast masking, bitMask[a]=0x1 << a private static final int[] bitMask = {0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x00000020, 0x00000040, 0x00000080, 0x00000100, 0x00000200, 0x00000400, 0x00000800, 0x00001000, 0x00002000, 0x00004000, 0x00008000, 0x00010000, 0x00020000, 0x00040000, 0x00080000, 0x00100000, 0x00200000, 0x00400000, 0x00800000, 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x00000000}; // pre-computed Bitmask for fast masking, rightMask[a]=0xffffffff >>> (32-a) private static final int[] reverseRightMask = {0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff};
Creates a new GF2Polynomial of the given length and value zero.
Params:
  • length – the desired number of bits to store
/** * Creates a new GF2Polynomial of the given <i>length</i> and value zero. * * @param length the desired number of bits to store */
public GF2Polynomial(int length) { int l = length; if (l < 1) { l = 1; } blocks = ((l - 1) >> 5) + 1; value = new int[blocks]; len = l; }
Creates a new GF2Polynomial of the given length and random value.
Params:
  • length – the desired number of bits to store
  • rand – SecureRandom to use for randomization
/** * Creates a new GF2Polynomial of the given <i>length</i> and random value. * * @param length the desired number of bits to store * @param rand SecureRandom to use for randomization */
public GF2Polynomial(int length, Random rand) { int l = length; if (l < 1) { l = 1; } blocks = ((l - 1) >> 5) + 1; value = new int[blocks]; len = l; randomize(rand); }
Creates a new GF2Polynomial of the given length and value selected by value:
  • ZERO
  • ONE
  • RANDOM
  • X
  • ALL
Params:
  • length – the desired number of bits to store
  • value – the value described by a String
/** * Creates a new GF2Polynomial of the given <i>length</i> and value * selected by <i>value</i>: * <UL> * <LI>ZERO</LI> * <LI>ONE</LI> * <LI>RANDOM</LI> * <LI>X</LI> * <LI>ALL</LI> * </UL> * * @param length the desired number of bits to store * @param value the value described by a String */
public GF2Polynomial(int length, String value) { int l = length; if (l < 1) { l = 1; } blocks = ((l - 1) >> 5) + 1; this.value = new int[blocks]; len = l; if (value.equalsIgnoreCase("ZERO")) { assignZero(); } else if (value.equalsIgnoreCase("ONE")) { assignOne(); } else if (value.equalsIgnoreCase("RANDOM")) { randomize(); } else if (value.equalsIgnoreCase("X")) { assignX(); } else if (value.equalsIgnoreCase("ALL")) { assignAll(); } else { throw new IllegalArgumentException( "Error: GF2Polynomial was called using " + value + " as value!"); } }
Creates a new GF2Polynomial of the given length using the given int[]. LSB is contained in bs[0].
Params:
  • length – the desired number of bits to store
  • bs – contains the desired value, LSB in bs[0]
/** * Creates a new GF2Polynomial of the given <i>length</i> using the given * int[]. LSB is contained in bs[0]. * * @param length the desired number of bits to store * @param bs contains the desired value, LSB in bs[0] */
public GF2Polynomial(int length, int[] bs) { int leng = length; if (leng < 1) { leng = 1; } blocks = ((leng - 1) >> 5) + 1; value = new int[blocks]; len = leng; int l = Math.min(blocks, bs.length); System.arraycopy(bs, 0, value, 0, l); zeroUnusedBits(); }
Creates a new GF2Polynomial by converting the given byte[] os according to 1363 and using the given length.
Params:
  • length – the intended length of this polynomial
  • os – the octet string to assign to this polynomial
See Also:
  • P1363 5.5.2 p22f, OS2BSP
/** * Creates a new GF2Polynomial by converting the given byte[] <i>os</i> * according to 1363 and using the given <i>length</i>. * * @param length the intended length of this polynomial * @param os the octet string to assign to this polynomial * @see "P1363 5.5.2 p22f, OS2BSP" */
public GF2Polynomial(int length, byte[] os) { int l = length; if (l < 1) { l = 1; } blocks = ((l - 1) >> 5) + 1; value = new int[blocks]; len = l; int i, m; int k = Math.min(((os.length - 1) >> 2) + 1, blocks); for (i = 0; i < k - 1; i++) { m = os.length - (i << 2) - 1; value[i] = (os[m]) & 0x000000ff; value[i] |= (os[m - 1] << 8) & 0x0000ff00; value[i] |= (os[m - 2] << 16) & 0x00ff0000; value[i] |= (os[m - 3] << 24) & 0xff000000; } i = k - 1; m = os.length - (i << 2) - 1; value[i] = os[m] & 0x000000ff; if (m > 0) { value[i] |= (os[m - 1] << 8) & 0x0000ff00; } if (m > 1) { value[i] |= (os[m - 2] << 16) & 0x00ff0000; } if (m > 2) { value[i] |= (os[m - 3] << 24) & 0xff000000; } zeroUnusedBits(); reduceN(); }
Creates a new GF2Polynomial by converting the given FlexiBigInt bi according to 1363 and using the given length.
Params:
  • length – the intended length of this polynomial
  • bi – the FlexiBigInt to assign to this polynomial
See Also:
  • P1363 5.5.1 p22, I2BSP
/** * Creates a new GF2Polynomial by converting the given FlexiBigInt <i>bi</i> * according to 1363 and using the given <i>length</i>. * * @param length the intended length of this polynomial * @param bi the FlexiBigInt to assign to this polynomial * @see "P1363 5.5.1 p22, I2BSP" */
public GF2Polynomial(int length, BigInteger bi) { int l = length; if (l < 1) { l = 1; } blocks = ((l - 1) >> 5) + 1; value = new int[blocks]; len = l; int i; byte[] val = bi.toByteArray(); if (val[0] == 0) { byte[] dummy = new byte[val.length - 1]; System.arraycopy(val, 1, dummy, 0, dummy.length); val = dummy; } int ov = val.length & 0x03; int k = ((val.length - 1) >> 2) + 1; for (i = 0; i < ov; i++) { value[k - 1] |= (val[i] & 0x000000ff) << ((ov - 1 - i) << 3); } int m = 0; for (i = 0; i <= (val.length - 4) >> 2; i++) { m = val.length - 1 - (i << 2); value[i] = (val[m]) & 0x000000ff; value[i] |= ((val[m - 1]) << 8) & 0x0000ff00; value[i] |= ((val[m - 2]) << 16) & 0x00ff0000; value[i] |= ((val[m - 3]) << 24) & 0xff000000; } if ((len & 0x1f) != 0) { value[blocks - 1] &= reverseRightMask[len & 0x1f]; } reduceN(); }
Creates a new GF2Polynomial by cloneing the given GF2Polynomial b.
Params:
  • b – the GF2Polynomial to clone
/** * Creates a new GF2Polynomial by cloneing the given GF2Polynomial <i>b</i>. * * @param b the GF2Polynomial to clone */
public GF2Polynomial(GF2Polynomial b) { len = b.len; blocks = b.blocks; value = IntUtils.clone(b.value); }
Returns:a copy of this GF2Polynomial
/** * @return a copy of this GF2Polynomial */
public Object clone() { return new GF2Polynomial(this); }
Returns the length of this GF2Polynomial. The length can be greater than the degree. To get the degree call reduceN() before calling getLength().
Returns:the length of this GF2Polynomial
/** * Returns the length of this GF2Polynomial. The length can be greater than * the degree. To get the degree call reduceN() before calling getLength(). * * @return the length of this GF2Polynomial */
public int getLength() { return len; }
Returns the value of this GF2Polynomial in an int[].
Returns:the value of this GF2Polynomial in a new int[], LSB in int[0]
/** * Returns the value of this GF2Polynomial in an int[]. * * @return the value of this GF2Polynomial in a new int[], LSB in int[0] */
public int[] toIntegerArray() { int[] result; result = new int[blocks]; System.arraycopy(value, 0, result, 0, blocks); return result; }
Returns a string representing this GF2Polynomials value using hexadecimal or binary radix in MSB-first order.
Params:
  • radix – the radix to use (2 or 16, otherwise 2 is used)
Returns:a String representing this GF2Polynomials value.
/** * Returns a string representing this GF2Polynomials value using hexadecimal * or binary radix in MSB-first order. * * @param radix the radix to use (2 or 16, otherwise 2 is used) * @return a String representing this GF2Polynomials value. */
public String toString(int radix) { final char[] HEX_CHARS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; final String[] BIN_CHARS = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"}; String res; int i; res = new String(); if (radix == 16) { for (i = blocks - 1; i >= 0; i--) { res += HEX_CHARS[(value[i] >>> 28) & 0x0f]; res += HEX_CHARS[(value[i] >>> 24) & 0x0f]; res += HEX_CHARS[(value[i] >>> 20) & 0x0f]; res += HEX_CHARS[(value[i] >>> 16) & 0x0f]; res += HEX_CHARS[(value[i] >>> 12) & 0x0f]; res += HEX_CHARS[(value[i] >>> 8) & 0x0f]; res += HEX_CHARS[(value[i] >>> 4) & 0x0f]; res += HEX_CHARS[(value[i]) & 0x0f]; res += " "; } } else { for (i = blocks - 1; i >= 0; i--) { res += BIN_CHARS[(value[i] >>> 28) & 0x0f]; res += BIN_CHARS[(value[i] >>> 24) & 0x0f]; res += BIN_CHARS[(value[i] >>> 20) & 0x0f]; res += BIN_CHARS[(value[i] >>> 16) & 0x0f]; res += BIN_CHARS[(value[i] >>> 12) & 0x0f]; res += BIN_CHARS[(value[i] >>> 8) & 0x0f]; res += BIN_CHARS[(value[i] >>> 4) & 0x0f]; res += BIN_CHARS[(value[i]) & 0x0f]; res += " "; } } return res; }
Converts this polynomial to a byte[] (octet string) according to 1363.
See Also:
  • P1363 5.5.2 p22f, BS2OSP
Returns:a byte[] representing the value of this polynomial
/** * Converts this polynomial to a byte[] (octet string) according to 1363. * * @return a byte[] representing the value of this polynomial * @see "P1363 5.5.2 p22f, BS2OSP" */
public byte[] toByteArray() { int k = ((len - 1) >> 3) + 1; int ov = k & 0x03; int m; byte[] res = new byte[k]; int i; for (i = 0; i < (k >> 2); i++) { m = k - (i << 2) - 1; res[m] = (byte)((value[i] & 0x000000ff)); res[m - 1] = (byte)((value[i] & 0x0000ff00) >>> 8); res[m - 2] = (byte)((value[i] & 0x00ff0000) >>> 16); res[m - 3] = (byte)((value[i] & 0xff000000) >>> 24); } for (i = 0; i < ov; i++) { m = (ov - i - 1) << 3; res[i] = (byte)((value[blocks - 1] & (0x000000ff << m)) >>> m); } return res; }
Converts this polynomial to an integer according to 1363.
See Also:
  • P1363 5.5.1 p22, BS2IP
Returns:a FlexiBigInt representing the value of this polynomial
/** * Converts this polynomial to an integer according to 1363. * * @return a FlexiBigInt representing the value of this polynomial * @see "P1363 5.5.1 p22, BS2IP" */
public BigInteger toFlexiBigInt() { if (len == 0 || isZero()) { return new BigInteger(0, new byte[0]); } return new BigInteger(1, toByteArray()); }
Sets the LSB to 1 and all other to 0, assigning 'one' to this GF2Polynomial.
/** * Sets the LSB to 1 and all other to 0, assigning 'one' to this * GF2Polynomial. */
public void assignOne() { int i; for (i = 1; i < blocks; i++) { value[i] = 0x00; } value[0] = 0x01; }
Sets Bit 1 to 1 and all other to 0, assigning 'x' to this GF2Polynomial.
/** * Sets Bit 1 to 1 and all other to 0, assigning 'x' to this GF2Polynomial. */
public void assignX() { int i; for (i = 1; i < blocks; i++) { value[i] = 0x00; } value[0] = 0x02; }
Sets all Bits to 1.
/** * Sets all Bits to 1. */
public void assignAll() { int i; for (i = 0; i < blocks; i++) { value[i] = 0xffffffff; } zeroUnusedBits(); }
Resets all bits to zero.
/** * Resets all bits to zero. */
public void assignZero() { int i; for (i = 0; i < blocks; i++) { value[i] = 0x00; } }
Fills all len bits of this GF2Polynomial with random values.
/** * Fills all len bits of this GF2Polynomial with random values. */
public void randomize() { int i; for (i = 0; i < blocks; i++) { value[i] = rand.nextInt(); } zeroUnusedBits(); }
Fills all len bits of this GF2Polynomial with random values using the specified source of randomness.
Params:
  • rand – the source of randomness
/** * Fills all len bits of this GF2Polynomial with random values using the * specified source of randomness. * * @param rand the source of randomness */
public void randomize(Random rand) { int i; for (i = 0; i < blocks; i++) { value[i] = rand.nextInt(); } zeroUnusedBits(); }
Returns true if two GF2Polynomials have the same size and value and thus are equal.
Params:
  • other – the other GF2Polynomial
Returns:true if this GF2Polynomial equals b (this == b)
/** * Returns true if two GF2Polynomials have the same size and value and thus * are equal. * * @param other the other GF2Polynomial * @return true if this GF2Polynomial equals <i>b</i> (<i>this</i> == * <i>b</i>) */
public boolean equals(Object other) { if (other == null || !(other instanceof GF2Polynomial)) { return false; } GF2Polynomial otherPol = (GF2Polynomial)other; if (len != otherPol.len) { return false; } for (int i = 0; i < blocks; i++) { if (value[i] != otherPol.value[i]) { return false; } } return true; }
Returns:the hash code of this polynomial
/** * @return the hash code of this polynomial */
public int hashCode() { return len + Arrays.hashCode(value); }
Tests if all bits equal zero.
Returns:true if this GF2Polynomial equals 'zero' (this == 0)
/** * Tests if all bits equal zero. * * @return true if this GF2Polynomial equals 'zero' (<i>this</i> == 0) */
public boolean isZero() { int i; if (len == 0) { return true; } for (i = 0; i < blocks; i++) { if (value[i] != 0) { return false; } } return true; }
Tests if all bits are reset to 0 and LSB is set to 1.
Returns:true if this GF2Polynomial equals 'one' (this == 1)
/** * Tests if all bits are reset to 0 and LSB is set to 1. * * @return true if this GF2Polynomial equals 'one' (<i>this</i> == 1) */
public boolean isOne() { int i; for (i = 1; i < blocks; i++) { if (value[i] != 0) { return false; } } if (value[0] != 0x01) { return false; } return true; }
Adds b to this GF2Polynomial and assigns the result to this GF2Polynomial. b can be of different size.
Params:
  • b – GF2Polynomial to add to this GF2Polynomial
/** * Adds <i>b</i> to this GF2Polynomial and assigns the result to this * GF2Polynomial. <i>b</i> can be of different size. * * @param b GF2Polynomial to add to this GF2Polynomial */
public void addToThis(GF2Polynomial b) { expandN(b.len); xorThisBy(b); }
Adds two GF2Polynomials, this and b, and returns the result. this and b can be of different size.
Params:
  • b – a GF2Polynomial
Returns:a new GF2Polynomial (this + b)
/** * Adds two GF2Polynomials, <i>this</i> and <i>b</i>, and returns the * result. <i>this</i> and <i>b</i> can be of different size. * * @param b a GF2Polynomial * @return a new GF2Polynomial (<i>this</i> + <i>b</i>) */
public GF2Polynomial add(GF2Polynomial b) { return xor(b); }
Subtracts b from this GF2Polynomial and assigns the result to this GF2Polynomial. b can be of different size.
Params:
  • b – a GF2Polynomial
/** * Subtracts <i>b</i> from this GF2Polynomial and assigns the result to * this GF2Polynomial. <i>b</i> can be of different size. * * @param b a GF2Polynomial */
public void subtractFromThis(GF2Polynomial b) { expandN(b.len); xorThisBy(b); }
Subtracts two GF2Polynomials, this and b, and returns the result in a new GF2Polynomial. this and b can be of different size.
Params:
  • b – a GF2Polynomial
Returns:a new GF2Polynomial (this - b)
/** * Subtracts two GF2Polynomials, <i>this</i> and <i>b</i>, and returns the * result in a new GF2Polynomial. <i>this</i> and <i>b</i> can be of * different size. * * @param b a GF2Polynomial * @return a new GF2Polynomial (<i>this</i> - <i>b</i>) */
public GF2Polynomial subtract(GF2Polynomial b) { return xor(b); }
Toggles the LSB of this GF2Polynomial, increasing its value by 'one'.
/** * Toggles the LSB of this GF2Polynomial, increasing its value by 'one'. */
public void increaseThis() { xorBit(0); }
Toggles the LSB of this GF2Polynomial, increasing the value by 'one' and returns the result in a new GF2Polynomial.
Returns:this + 1
/** * Toggles the LSB of this GF2Polynomial, increasing the value by 'one' and * returns the result in a new GF2Polynomial. * * @return <tt>this + 1</tt> */
public GF2Polynomial increase() { GF2Polynomial result = new GF2Polynomial(this); result.increaseThis(); return result; }
Multiplies this GF2Polynomial with b and returns the result in a new GF2Polynomial. This method does not reduce the result in GF(2^N). This method uses classic multiplication (schoolbook).
Params:
  • b – a GF2Polynomial
Returns:a new GF2Polynomial (this * b)
/** * Multiplies this GF2Polynomial with <i>b</i> and returns the result in a * new GF2Polynomial. This method does not reduce the result in GF(2^N). * This method uses classic multiplication (schoolbook). * * @param b a GF2Polynomial * @return a new GF2Polynomial (<i>this</i> * <i>b</i>) */
public GF2Polynomial multiplyClassic(GF2Polynomial b) { GF2Polynomial result = new GF2Polynomial(Math.max(len, b.len) << 1); GF2Polynomial[] m = new GF2Polynomial[32]; int i, j; m[0] = new GF2Polynomial(this); for (i = 1; i <= 31; i++) { m[i] = m[i - 1].shiftLeft(); } for (i = 0; i < b.blocks; i++) { for (j = 0; j <= 31; j++) { if ((b.value[i] & bitMask[j]) != 0) { result.xorThisBy(m[j]); } } for (j = 0; j <= 31; j++) { m[j].shiftBlocksLeft(); } } return result; }
Multiplies this GF2Polynomial with b and returns the result in a new GF2Polynomial. This method does not reduce the result in GF(2^N). This method uses Karatzuba multiplication.
Params:
  • b – a GF2Polynomial
Returns:a new GF2Polynomial (this * b)
/** * Multiplies this GF2Polynomial with <i>b</i> and returns the result in a * new GF2Polynomial. This method does not reduce the result in GF(2^N). * This method uses Karatzuba multiplication. * * @param b a GF2Polynomial * @return a new GF2Polynomial (<i>this</i> * <i>b</i>) */
public GF2Polynomial multiply(GF2Polynomial b) { int n = Math.max(len, b.len); expandN(n); b.expandN(n); return karaMult(b); }
Does the recursion for Karatzuba multiplication.
/** * Does the recursion for Karatzuba multiplication. */
private GF2Polynomial karaMult(GF2Polynomial b) { GF2Polynomial result = new GF2Polynomial(len << 1); if (len <= 32) { result.value = mult32(value[0], b.value[0]); return result; } if (len <= 64) { result.value = mult64(value, b.value); return result; } if (len <= 128) { result.value = mult128(value, b.value); return result; } if (len <= 256) { result.value = mult256(value, b.value); return result; } if (len <= 512) { result.value = mult512(value, b.value); return result; } int n = IntegerFunctions.floorLog(len - 1); n = bitMask[n]; GF2Polynomial a0 = lower(((n - 1) >> 5) + 1); GF2Polynomial a1 = upper(((n - 1) >> 5) + 1); GF2Polynomial b0 = b.lower(((n - 1) >> 5) + 1); GF2Polynomial b1 = b.upper(((n - 1) >> 5) + 1); GF2Polynomial c = a1.karaMult(b1); // c = a1*b1 GF2Polynomial e = a0.karaMult(b0); // e = a0*b0 a0.addToThis(a1); // a0 = a0 + a1 b0.addToThis(b1); // b0 = b0 + b1 GF2Polynomial d = a0.karaMult(b0); // d = (a0+a1)*(b0+b1) result.shiftLeftAddThis(c, n << 1); result.shiftLeftAddThis(c, n); result.shiftLeftAddThis(d, n); result.shiftLeftAddThis(e, n); result.addToThis(e); return result; }
16-Integer Version of Karatzuba multiplication.
/** * 16-Integer Version of Karatzuba multiplication. */
private static int[] mult512(int[] a, int[] b) { int[] result = new int[32]; int[] a0 = new int[8]; System.arraycopy(a, 0, a0, 0, Math.min(8, a.length)); int[] a1 = new int[8]; if (a.length > 8) { System.arraycopy(a, 8, a1, 0, Math.min(8, a.length - 8)); } int[] b0 = new int[8]; System.arraycopy(b, 0, b0, 0, Math.min(8, b.length)); int[] b1 = new int[8]; if (b.length > 8) { System.arraycopy(b, 8, b1, 0, Math.min(8, b.length - 8)); } int[] c = mult256(a1, b1); result[31] ^= c[15]; result[30] ^= c[14]; result[29] ^= c[13]; result[28] ^= c[12]; result[27] ^= c[11]; result[26] ^= c[10]; result[25] ^= c[9]; result[24] ^= c[8]; result[23] ^= c[7] ^ c[15]; result[22] ^= c[6] ^ c[14]; result[21] ^= c[5] ^ c[13]; result[20] ^= c[4] ^ c[12]; result[19] ^= c[3] ^ c[11]; result[18] ^= c[2] ^ c[10]; result[17] ^= c[1] ^ c[9]; result[16] ^= c[0] ^ c[8]; result[15] ^= c[7]; result[14] ^= c[6]; result[13] ^= c[5]; result[12] ^= c[4]; result[11] ^= c[3]; result[10] ^= c[2]; result[9] ^= c[1]; result[8] ^= c[0]; a1[0] ^= a0[0]; a1[1] ^= a0[1]; a1[2] ^= a0[2]; a1[3] ^= a0[3]; a1[4] ^= a0[4]; a1[5] ^= a0[5]; a1[6] ^= a0[6]; a1[7] ^= a0[7]; b1[0] ^= b0[0]; b1[1] ^= b0[1]; b1[2] ^= b0[2]; b1[3] ^= b0[3]; b1[4] ^= b0[4]; b1[5] ^= b0[5]; b1[6] ^= b0[6]; b1[7] ^= b0[7]; int[] d = mult256(a1, b1); result[23] ^= d[15]; result[22] ^= d[14]; result[21] ^= d[13]; result[20] ^= d[12]; result[19] ^= d[11]; result[18] ^= d[10]; result[17] ^= d[9]; result[16] ^= d[8]; result[15] ^= d[7]; result[14] ^= d[6]; result[13] ^= d[5]; result[12] ^= d[4]; result[11] ^= d[3]; result[10] ^= d[2]; result[9] ^= d[1]; result[8] ^= d[0]; int[] e = mult256(a0, b0); result[23] ^= e[15]; result[22] ^= e[14]; result[21] ^= e[13]; result[20] ^= e[12]; result[19] ^= e[11]; result[18] ^= e[10]; result[17] ^= e[9]; result[16] ^= e[8]; result[15] ^= e[7] ^ e[15]; result[14] ^= e[6] ^ e[14]; result[13] ^= e[5] ^ e[13]; result[12] ^= e[4] ^ e[12]; result[11] ^= e[3] ^ e[11]; result[10] ^= e[2] ^ e[10]; result[9] ^= e[1] ^ e[9]; result[8] ^= e[0] ^ e[8]; result[7] ^= e[7]; result[6] ^= e[6]; result[5] ^= e[5]; result[4] ^= e[4]; result[3] ^= e[3]; result[2] ^= e[2]; result[1] ^= e[1]; result[0] ^= e[0]; return result; }
8-Integer Version of Karatzuba multiplication.
/** * 8-Integer Version of Karatzuba multiplication. */
private static int[] mult256(int[] a, int[] b) { int[] result = new int[16]; int[] a0 = new int[4]; System.arraycopy(a, 0, a0, 0, Math.min(4, a.length)); int[] a1 = new int[4]; if (a.length > 4) { System.arraycopy(a, 4, a1, 0, Math.min(4, a.length - 4)); } int[] b0 = new int[4]; System.arraycopy(b, 0, b0, 0, Math.min(4, b.length)); int[] b1 = new int[4]; if (b.length > 4) { System.arraycopy(b, 4, b1, 0, Math.min(4, b.length - 4)); } if (a1[3] == 0 && a1[2] == 0 && b1[3] == 0 && b1[2] == 0) { if (a1[1] == 0 && b1[1] == 0) { if (a1[0] != 0 || b1[0] != 0) { // [3]=[2]=[1]=0, [0]!=0 int[] c = mult32(a1[0], b1[0]); result[9] ^= c[1]; result[8] ^= c[0]; result[5] ^= c[1]; result[4] ^= c[0]; } } else { // [3]=[2]=0 [1]!=0, [0]!=0 int[] c = mult64(a1, b1); result[11] ^= c[3]; result[10] ^= c[2]; result[9] ^= c[1]; result[8] ^= c[0]; result[7] ^= c[3]; result[6] ^= c[2]; result[5] ^= c[1]; result[4] ^= c[0]; } } else { // [3]!=0 [2]!=0 [1]!=0, [0]!=0 int[] c = mult128(a1, b1); result[15] ^= c[7]; result[14] ^= c[6]; result[13] ^= c[5]; result[12] ^= c[4]; result[11] ^= c[3] ^ c[7]; result[10] ^= c[2] ^ c[6]; result[9] ^= c[1] ^ c[5]; result[8] ^= c[0] ^ c[4]; result[7] ^= c[3]; result[6] ^= c[2]; result[5] ^= c[1]; result[4] ^= c[0]; } a1[0] ^= a0[0]; a1[1] ^= a0[1]; a1[2] ^= a0[2]; a1[3] ^= a0[3]; b1[0] ^= b0[0]; b1[1] ^= b0[1]; b1[2] ^= b0[2]; b1[3] ^= b0[3]; int[] d = mult128(a1, b1); result[11] ^= d[7]; result[10] ^= d[6]; result[9] ^= d[5]; result[8] ^= d[4]; result[7] ^= d[3]; result[6] ^= d[2]; result[5] ^= d[1]; result[4] ^= d[0]; int[] e = mult128(a0, b0); result[11] ^= e[7]; result[10] ^= e[6]; result[9] ^= e[5]; result[8] ^= e[4]; result[7] ^= e[3] ^ e[7]; result[6] ^= e[2] ^ e[6]; result[5] ^= e[1] ^ e[5]; result[4] ^= e[0] ^ e[4]; result[3] ^= e[3]; result[2] ^= e[2]; result[1] ^= e[1]; result[0] ^= e[0]; return result; }
4-Integer Version of Karatzuba multiplication.
/** * 4-Integer Version of Karatzuba multiplication. */
private static int[] mult128(int[] a, int[] b) { int[] result = new int[8]; int[] a0 = new int[2]; System.arraycopy(a, 0, a0, 0, Math.min(2, a.length)); int[] a1 = new int[2]; if (a.length > 2) { System.arraycopy(a, 2, a1, 0, Math.min(2, a.length - 2)); } int[] b0 = new int[2]; System.arraycopy(b, 0, b0, 0, Math.min(2, b.length)); int[] b1 = new int[2]; if (b.length > 2) { System.arraycopy(b, 2, b1, 0, Math.min(2, b.length - 2)); } if (a1[1] == 0 && b1[1] == 0) { if (a1[0] != 0 || b1[0] != 0) { int[] c = mult32(a1[0], b1[0]); result[5] ^= c[1]; result[4] ^= c[0]; result[3] ^= c[1]; result[2] ^= c[0]; } } else { int[] c = mult64(a1, b1); result[7] ^= c[3]; result[6] ^= c[2]; result[5] ^= c[1] ^ c[3]; result[4] ^= c[0] ^ c[2]; result[3] ^= c[1]; result[2] ^= c[0]; } a1[0] ^= a0[0]; a1[1] ^= a0[1]; b1[0] ^= b0[0]; b1[1] ^= b0[1]; if (a1[1] == 0 && b1[1] == 0) { int[] d = mult32(a1[0], b1[0]); result[3] ^= d[1]; result[2] ^= d[0]; } else { int[] d = mult64(a1, b1); result[5] ^= d[3]; result[4] ^= d[2]; result[3] ^= d[1]; result[2] ^= d[0]; } if (a0[1] == 0 && b0[1] == 0) { int[] e = mult32(a0[0], b0[0]); result[3] ^= e[1]; result[2] ^= e[0]; result[1] ^= e[1]; result[0] ^= e[0]; } else { int[] e = mult64(a0, b0); result[5] ^= e[3]; result[4] ^= e[2]; result[3] ^= e[1] ^ e[3]; result[2] ^= e[0] ^ e[2]; result[1] ^= e[1]; result[0] ^= e[0]; } return result; }
2-Integer Version of Karatzuba multiplication.
/** * 2-Integer Version of Karatzuba multiplication. */
private static int[] mult64(int[] a, int[] b) { int[] result = new int[4]; int a0 = a[0]; int a1 = 0; if (a.length > 1) { a1 = a[1]; } int b0 = b[0]; int b1 = 0; if (b.length > 1) { b1 = b[1]; } if (a1 != 0 || b1 != 0) { int[] c = mult32(a1, b1); result[3] ^= c[1]; result[2] ^= c[0] ^ c[1]; result[1] ^= c[0]; } int[] d = mult32(a0 ^ a1, b0 ^ b1); result[2] ^= d[1]; result[1] ^= d[0]; int[] e = mult32(a0, b0); result[2] ^= e[1]; result[1] ^= e[0] ^ e[1]; result[0] ^= e[0]; return result; }
4-Byte Version of Karatzuba multiplication. Here the actual work is done.
/** * 4-Byte Version of Karatzuba multiplication. Here the actual work is done. */
private static int[] mult32(int a, int b) { int[] result = new int[2]; if (a == 0 || b == 0) { return result; } long b2 = b; b2 &= 0x00000000ffffffffL; int i; long h = 0; for (i = 1; i <= 32; i++) { if ((a & bitMask[i - 1]) != 0) { h ^= b2; } b2 <<= 1; } result[1] = (int)(h >>> 32); result[0] = (int)(h & 0x00000000ffffffffL); return result; }
Returns a new GF2Polynomial containing the upper k bytes of this GF2Polynomial.
Params:
  • k –
See Also:
Returns:a new GF2Polynomial containing the upper k bytes of this GF2Polynomial
/** * Returns a new GF2Polynomial containing the upper <i>k</i> bytes of this * GF2Polynomial. * * @param k * @return a new GF2Polynomial containing the upper <i>k</i> bytes of this * GF2Polynomial * @see GF2Polynomial#karaMult */
private GF2Polynomial upper(int k) { int j = Math.min(k, blocks - k); GF2Polynomial result = new GF2Polynomial(j << 5); if (blocks >= k) { System.arraycopy(value, k, result.value, 0, j); } return result; }
Returns a new GF2Polynomial containing the lower k bytes of this GF2Polynomial.
Params:
  • k –
See Also:
Returns:a new GF2Polynomial containing the lower k bytes of this GF2Polynomial
/** * Returns a new GF2Polynomial containing the lower <i>k</i> bytes of this * GF2Polynomial. * * @param k * @return a new GF2Polynomial containing the lower <i>k</i> bytes of this * GF2Polynomial * @see GF2Polynomial#karaMult */
private GF2Polynomial lower(int k) { GF2Polynomial result = new GF2Polynomial(k << 5); System.arraycopy(value, 0, result.value, 0, Math.min(k, blocks)); return result; }
Returns the remainder of this divided by g in a new GF2Polynomial.
Params:
  • g – GF2Polynomial != 0
Returns:a new GF2Polynomial (this % g)
/** * Returns the remainder of <i>this</i> divided by <i>g</i> in a new * GF2Polynomial. * * @param g GF2Polynomial != 0 * @return a new GF2Polynomial (<i>this</i> % <i>g</i>) */
public GF2Polynomial remainder(GF2Polynomial g) throws RuntimeException { /* a div b = q / r */ GF2Polynomial a = new GF2Polynomial(this); GF2Polynomial b = new GF2Polynomial(g); GF2Polynomial j; int i; if (b.isZero()) { throw new RuntimeException(); } a.reduceN(); b.reduceN(); if (a.len < b.len) { return a; } i = a.len - b.len; while (i >= 0) { j = b.shiftLeft(i); a.subtractFromThis(j); a.reduceN(); i = a.len - b.len; } return a; }
Returns the absolute quotient of this divided by g in a new GF2Polynomial.
Params:
  • g – GF2Polynomial != 0
Returns:a new GF2Polynomial |_ this / g _|
/** * Returns the absolute quotient of <i>this</i> divided by <i>g</i> in a * new GF2Polynomial. * * @param g GF2Polynomial != 0 * @return a new GF2Polynomial |_ <i>this</i> / <i>g</i> _| */
public GF2Polynomial quotient(GF2Polynomial g) throws RuntimeException { /* a div b = q / r */ GF2Polynomial q = new GF2Polynomial(len); GF2Polynomial a = new GF2Polynomial(this); GF2Polynomial b = new GF2Polynomial(g); GF2Polynomial j; int i; if (b.isZero()) { throw new RuntimeException(); } a.reduceN(); b.reduceN(); if (a.len < b.len) { return new GF2Polynomial(0); } i = a.len - b.len; q.expandN(i + 1); while (i >= 0) { j = b.shiftLeft(i); a.subtractFromThis(j); a.reduceN(); q.xorBit(i); i = a.len - b.len; } return q; }
Divides this by g and returns the quotient and remainder in a new GF2Polynomial[2], quotient in [0], remainder in [1].
Params:
  • g – GF2Polynomial != 0
Returns:a new GF2Polynomial[2] containing quotient and remainder
/** * Divides <i>this</i> by <i>g</i> and returns the quotient and remainder * in a new GF2Polynomial[2], quotient in [0], remainder in [1]. * * @param g GF2Polynomial != 0 * @return a new GF2Polynomial[2] containing quotient and remainder */
public GF2Polynomial[] divide(GF2Polynomial g) throws RuntimeException { /* a div b = q / r */ GF2Polynomial[] result = new GF2Polynomial[2]; GF2Polynomial q = new GF2Polynomial(len); GF2Polynomial a = new GF2Polynomial(this); GF2Polynomial b = new GF2Polynomial(g); GF2Polynomial j; int i; if (b.isZero()) { throw new RuntimeException(); } a.reduceN(); b.reduceN(); if (a.len < b.len) { result[0] = new GF2Polynomial(0); result[1] = a; return result; } i = a.len - b.len; q.expandN(i + 1); while (i >= 0) { j = b.shiftLeft(i); a.subtractFromThis(j); a.reduceN(); q.xorBit(i); i = a.len - b.len; } result[0] = q; result[1] = a; return result; }
Returns the greatest common divisor of this and g in a new GF2Polynomial.
Params:
  • g – GF2Polynomial != 0
Throws:
Returns:a new GF2Polynomial gcd(this,g)
/** * Returns the greatest common divisor of <i>this</i> and <i>g</i> in a * new GF2Polynomial. * * @param g GF2Polynomial != 0 * @return a new GF2Polynomial gcd(<i>this</i>,<i>g</i>) * @throws ArithmeticException if <i>this</i> and <i>g</i> both are equal to zero */
public GF2Polynomial gcd(GF2Polynomial g) throws RuntimeException { if (isZero() && g.isZero()) { throw new ArithmeticException("Both operands of gcd equal zero."); } if (isZero()) { return new GF2Polynomial(g); } if (g.isZero()) { return new GF2Polynomial(this); } GF2Polynomial a = new GF2Polynomial(this); GF2Polynomial b = new GF2Polynomial(g); GF2Polynomial c; while (!b.isZero()) { c = a.remainder(b); a = b; b = c; } return a; }
Checks if this is irreducible, according to IEEE P1363, A.5.5, p103.
Note: The algorithm from IEEE P1363, A5.5 can be used to check a polynomial with coefficients in GF(2^r) for irreducibility. As this class only represents polynomials with coefficients in GF(2), the algorithm is adapted to the case r=1.
See Also:
  • P1363, A.5.5, p103
Returns:true if this is irreducible
/** * Checks if <i>this</i> is irreducible, according to IEEE P1363, A.5.5, * p103.<br> * Note: The algorithm from IEEE P1363, A5.5 can be used to check a * polynomial with coefficients in GF(2^r) for irreducibility. As this class * only represents polynomials with coefficients in GF(2), the algorithm is * adapted to the case r=1. * * @return true if <i>this</i> is irreducible * @see "P1363, A.5.5, p103" */
public boolean isIrreducible() { if (isZero()) { return false; } GF2Polynomial f = new GF2Polynomial(this); int d, i; GF2Polynomial u, g; GF2Polynomial dummy; f.reduceN(); d = f.len - 1; u = new GF2Polynomial(f.len, "X"); for (i = 1; i <= (d >> 1); i++) { u.squareThisPreCalc(); u = u.remainder(f); dummy = u.add(new GF2Polynomial(32, "X")); if (!dummy.isZero()) { g = f.gcd(dummy); if (!g.isOne()) { return false; } } else { return false; } } return true; }
Reduces this GF2Polynomial using the trinomial x^m + x^tc + 1.
Params:
  • m – the degree of the used field
  • tc – degree of the middle x in the trinomial
/** * Reduces this GF2Polynomial using the trinomial x^<i>m</i> + x^<i>tc</i> + * 1. * * @param m the degree of the used field * @param tc degree of the middle x in the trinomial */
void reduceTrinomial(int m, int tc) { int i; int p0, p1; int q0, q1; long t; p0 = m >>> 5; // block which contains 2^m q0 = 32 - (m & 0x1f); // (32-index) of 2^m within block p0 p1 = (m - tc) >>> 5; // block which contains 2^tc q1 = 32 - ((m - tc) & 0x1f); // (32-index) of 2^tc within block q1 int max = ((m << 1) - 2) >>> 5; // block which contains 2^(2m-2) int min = p0; // block which contains 2^m for (i = max; i > min; i--) { // for i = maxBlock to minBlock // reduce coefficients contained in t // t = block[i] t = value[i] & 0x00000000ffffffffL; // block[i-p0-1] ^= t << q0 value[i - p0 - 1] ^= (int)(t << q0); // block[i-p0] ^= t >>> (32-q0) value[i - p0] ^= t >>> (32 - q0); // block[i-p1-1] ^= << q1 value[i - p1 - 1] ^= (int)(t << q1); // block[i-p1] ^= t >>> (32-q1) value[i - p1] ^= t >>> (32 - q1); value[i] = 0x00; } // reduce last coefficients in block containing 2^m t = value[min] & 0x00000000ffffffffL & (0xffffffffL << (m & 0x1f)); // t // contains the last coefficients > m value[0] ^= t >>> (32 - q0); if (min - p1 - 1 >= 0) { value[min - p1 - 1] ^= (int)(t << q1); } value[min - p1] ^= t >>> (32 - q1); value[min] &= reverseRightMask[m & 0x1f]; blocks = ((m - 1) >>> 5) + 1; len = m; }
Reduces this GF2Polynomial using the pentanomial x^m + x^pc[2] + x^pc[1] + x^pc[0] + 1.
Params:
  • m – the degree of the used field
  • pc – degrees of the middle x's in the pentanomial
/** * Reduces this GF2Polynomial using the pentanomial x^<i>m</i> + x^<i>pc[2]</i> + * x^<i>pc[1]</i> + x^<i>pc[0]</i> + 1. * * @param m the degree of the used field * @param pc degrees of the middle x's in the pentanomial */
void reducePentanomial(int m, int[] pc) { int i; int p0, p1, p2, p3; int q0, q1, q2, q3; long t; p0 = m >>> 5; q0 = 32 - (m & 0x1f); p1 = (m - pc[0]) >>> 5; q1 = 32 - ((m - pc[0]) & 0x1f); p2 = (m - pc[1]) >>> 5; q2 = 32 - ((m - pc[1]) & 0x1f); p3 = (m - pc[2]) >>> 5; q3 = 32 - ((m - pc[2]) & 0x1f); int max = ((m << 1) - 2) >>> 5; int min = p0; for (i = max; i > min; i--) { t = value[i] & 0x00000000ffffffffL; value[i - p0 - 1] ^= (int)(t << q0); value[i - p0] ^= t >>> (32 - q0); value[i - p1 - 1] ^= (int)(t << q1); value[i - p1] ^= t >>> (32 - q1); value[i - p2 - 1] ^= (int)(t << q2); value[i - p2] ^= t >>> (32 - q2); value[i - p3 - 1] ^= (int)(t << q3); value[i - p3] ^= t >>> (32 - q3); value[i] = 0; } t = value[min] & 0x00000000ffffffffL & (0xffffffffL << (m & 0x1f)); value[0] ^= t >>> (32 - q0); if (min - p1 - 1 >= 0) { value[min - p1 - 1] ^= (int)(t << q1); } value[min - p1] ^= t >>> (32 - q1); if (min - p2 - 1 >= 0) { value[min - p2 - 1] ^= (int)(t << q2); } value[min - p2] ^= t >>> (32 - q2); if (min - p3 - 1 >= 0) { value[min - p3 - 1] ^= (int)(t << q3); } value[min - p3] ^= t >>> (32 - q3); value[min] &= reverseRightMask[m & 0x1f]; blocks = ((m - 1) >>> 5) + 1; len = m; }
Reduces len by finding the most significant bit set to one and reducing len and blocks.
/** * Reduces len by finding the most significant bit set to one and reducing * len and blocks. */
public void reduceN() { int i, j, h; i = blocks - 1; while ((value[i] == 0) && (i > 0)) { i--; } h = value[i]; j = 0; while (h != 0) { h >>>= 1; j++; } len = (i << 5) + j; blocks = i + 1; }
Expands len and int[] value to i. This is useful before adding two GF2Polynomials of different size.
Params:
  • i – the intended length
/** * Expands len and int[] value to <i>i</i>. This is useful before adding * two GF2Polynomials of different size. * * @param i the intended length */
public void expandN(int i) { int k; int[] bs; if (len >= i) { return; } len = i; k = ((i - 1) >>> 5) + 1; if (blocks >= k) { return; } if (value.length >= k) { int j; for (j = blocks; j < k; j++) { value[j] = 0; } blocks = k; return; } bs = new int[k]; System.arraycopy(value, 0, bs, 0, blocks); blocks = k; value = null; value = bs; }
Squares this GF2Polynomial and expands it accordingly. This method does not reduce the result in GF(2^N). There exists a faster method for squaring in GF(2^N).
See Also:
  • square.square
/** * Squares this GF2Polynomial and expands it accordingly. This method does * not reduce the result in GF(2^N). There exists a faster method for * squaring in GF(2^N). * * @see GF2nPolynomialElement#square */
public void squareThisBitwise() { int i, h, j, k; if (isZero()) { return; } int[] result = new int[blocks << 1]; for (i = blocks - 1; i >= 0; i--) { h = value[i]; j = 0x00000001; for (k = 0; k < 16; k++) { if ((h & 0x01) != 0) { result[i << 1] |= j; } if ((h & 0x00010000) != 0) { result[(i << 1) + 1] |= j; } j <<= 2; h >>>= 1; } } value = null; value = result; blocks = result.length; len = (len << 1) - 1; }
Squares this GF2Polynomial by using precomputed values of squaringTable. This method does not reduce the result in GF(2^N).
/** * Squares this GF2Polynomial by using precomputed values of squaringTable. * This method does not reduce the result in GF(2^N). */
public void squareThisPreCalc() { int i; if (isZero()) { return; } if (value.length >= (blocks << 1)) { for (i = blocks - 1; i >= 0; i--) { value[(i << 1) + 1] = GF2Polynomial.squaringTable[(value[i] & 0x00ff0000) >>> 16] | (GF2Polynomial.squaringTable[(value[i] & 0xff000000) >>> 24] << 16); value[i << 1] = GF2Polynomial.squaringTable[value[i] & 0x000000ff] | (GF2Polynomial.squaringTable[(value[i] & 0x0000ff00) >>> 8] << 16); } blocks <<= 1; len = (len << 1) - 1; } else { int[] result = new int[blocks << 1]; for (i = 0; i < blocks; i++) { result[i << 1] = GF2Polynomial.squaringTable[value[i] & 0x000000ff] | (GF2Polynomial.squaringTable[(value[i] & 0x0000ff00) >>> 8] << 16); result[(i << 1) + 1] = GF2Polynomial.squaringTable[(value[i] & 0x00ff0000) >>> 16] | (GF2Polynomial.squaringTable[(value[i] & 0xff000000) >>> 24] << 16); } value = null; value = result; blocks <<= 1; len = (len << 1) - 1; } }
Does a vector-multiplication modulo 2 and returns the result as boolean.
Params:
  • b – GF2Polynomial
Returns:this x b as boolean (1->true, 0->false)
/** * Does a vector-multiplication modulo 2 and returns the result as boolean. * * @param b GF2Polynomial * @return this x <i>b</i> as boolean (1-&gt;true, 0-&gt;false) */
public boolean vectorMult(GF2Polynomial b) throws RuntimeException { int i; int h; boolean result = false; if (len != b.len) { throw new RuntimeException(); } for (i = 0; i < blocks; i++) { h = value[i] & b.value[i]; result ^= parity[h & 0x000000ff]; result ^= parity[(h >>> 8) & 0x000000ff]; result ^= parity[(h >>> 16) & 0x000000ff]; result ^= parity[(h >>> 24) & 0x000000ff]; } return result; }
Returns the bitwise exclusive-or of this and b in a new GF2Polynomial. this and b can be of different size.
Params:
  • b – GF2Polynomial
Returns:a new GF2Polynomial (this ^ b)
/** * Returns the bitwise exclusive-or of <i>this</i> and <i>b</i> in a new * GF2Polynomial. <i>this</i> and <i>b</i> can be of different size. * * @param b GF2Polynomial * @return a new GF2Polynomial (<i>this</i> ^ <i>b</i>) */
public GF2Polynomial xor(GF2Polynomial b) { int i; GF2Polynomial result; int k = Math.min(blocks, b.blocks); if (len >= b.len) { result = new GF2Polynomial(this); for (i = 0; i < k; i++) { result.value[i] ^= b.value[i]; } } else { result = new GF2Polynomial(b); for (i = 0; i < k; i++) { result.value[i] ^= value[i]; } } // If we xor'ed some bits too many by proceeding blockwise, // restore them to zero: result.zeroUnusedBits(); return result; }
Computes the bitwise exclusive-or of this GF2Polynomial and b and stores the result in this GF2Polynomial. b can be of different size.
Params:
  • b – GF2Polynomial
/** * Computes the bitwise exclusive-or of this GF2Polynomial and <i>b</i> and * stores the result in this GF2Polynomial. <i>b</i> can be of different * size. * * @param b GF2Polynomial */
public void xorThisBy(GF2Polynomial b) { int i; for (i = 0; i < Math.min(blocks, b.blocks); i++) { value[i] ^= b.value[i]; } // If we xor'ed some bits too many by proceeding blockwise, // restore them to zero: zeroUnusedBits(); }
If len is not a multiple of the block size (32), some extra bits of the last block might have been modified during a blockwise operation. This method compensates for that by restoring these "extra" bits to zero.
/** * If {@link #len} is not a multiple of the block size (32), some extra bits * of the last block might have been modified during a blockwise operation. * This method compensates for that by restoring these "extra" bits to zero. */
private void zeroUnusedBits() { if ((len & 0x1f) != 0) { value[blocks - 1] &= reverseRightMask[len & 0x1f]; } }
Sets the bit at position i.
Params:
  • i – int
Throws:
/** * Sets the bit at position <i>i</i>. * * @param i int * @throws RuntimeException if (<i>i</i> &lt; 0) || (<i>i</i> &gt; (len - 1)) */
public void setBit(int i) throws RuntimeException { if (i < 0 || i > (len - 1)) { throw new RuntimeException(); } value[i >>> 5] |= bitMask[i & 0x1f]; return; }
Returns the bit at position i.
Params:
  • i – int
Returns:the bit at position i if i is a valid position, 0 otherwise.
/** * Returns the bit at position <i>i</i>. * * @param i int * @return the bit at position <i>i</i> if <i>i</i> is a valid position, 0 * otherwise. */
public int getBit(int i) { if (i < 0) { throw new RuntimeException(); } if (i > (len - 1)) { return 0; } return ((value[i >>> 5] & bitMask[i & 0x1f]) != 0) ? 1 : 0; }
Resets the bit at position i.
Params:
  • i – int
Throws:
/** * Resets the bit at position <i>i</i>. * * @param i int * @throws RuntimeException if (<i>i</i> &lt; 0) || (<i>i</i> &gt; (len - 1)) */
public void resetBit(int i) throws RuntimeException { if (i < 0) { throw new RuntimeException(); } if (i > (len - 1)) { return; } value[i >>> 5] &= ~bitMask[i & 0x1f]; }
Xors the bit at position i.
Params:
  • i – int
Throws:
/** * Xors the bit at position <i>i</i>. * * @param i int * @throws RuntimeException if (<i>i</i> &lt; 0) || (<i>i</i> &gt; (len - 1)) */
public void xorBit(int i) throws RuntimeException { if (i < 0 || i > (len - 1)) { throw new RuntimeException(); } value[i >>> 5] ^= bitMask[i & 0x1f]; }
Tests the bit at position i.
Params:
  • i – the position of the bit to be tested
Returns:true if the bit at position i is set (a(i) == 1). False if (i < 0) || (i > (len - 1))
/** * Tests the bit at position <i>i</i>. * * @param i the position of the bit to be tested * @return true if the bit at position <i>i</i> is set (a(<i>i</i>) == * 1). False if (<i>i</i> &lt; 0) || (<i>i</i> &gt; (len - 1)) */
public boolean testBit(int i) { if (i < 0) { throw new RuntimeException(); } if (i > (len - 1)) { return false; } return (value[i >>> 5] & bitMask[i & 0x1f]) != 0; }
Returns this GF2Polynomial shift-left by 1 in a new GF2Polynomial.
Returns:a new GF2Polynomial (this << 1)
/** * Returns this GF2Polynomial shift-left by 1 in a new GF2Polynomial. * * @return a new GF2Polynomial (this &lt;&lt; 1) */
public GF2Polynomial shiftLeft() { GF2Polynomial result = new GF2Polynomial(len + 1, value); int i; for (i = result.blocks - 1; i >= 1; i--) { result.value[i] <<= 1; result.value[i] |= result.value[i - 1] >>> 31; } result.value[0] <<= 1; return result; }
Shifts-left this by one and enlarges the size of value if necesary.
/** * Shifts-left this by one and enlarges the size of value if necesary. */
public void shiftLeftThis() { /** @todo This is untested. */ int i; if ((len & 0x1f) == 0) { // check if blocks increases len += 1; blocks += 1; if (blocks > value.length) { // enlarge value int[] bs = new int[blocks]; System.arraycopy(value, 0, bs, 0, value.length); value = null; value = bs; } for (i = blocks - 1; i >= 1; i--) { value[i] |= value[i - 1] >>> 31; value[i - 1] <<= 1; } } else { len += 1; for (i = blocks - 1; i >= 1; i--) { value[i] <<= 1; value[i] |= value[i - 1] >>> 31; } value[0] <<= 1; } }
Returns this GF2Polynomial shift-left by k in a new GF2Polynomial.
Params:
  • k – int
Returns:a new GF2Polynomial (this << k)
/** * Returns this GF2Polynomial shift-left by <i>k</i> in a new * GF2Polynomial. * * @param k int * @return a new GF2Polynomial (this &lt;&lt; <i>k</i>) */
public GF2Polynomial shiftLeft(int k) { // Variant 2, requiring a modified shiftBlocksLeft(k) // In case of modification, consider a rename to doShiftBlocksLeft() // with an explicit note that this method assumes that the polynomial // has already been resized. Or consider doing things inline. // Construct the resulting polynomial of appropriate length: GF2Polynomial result = new GF2Polynomial(len + k, value); // Shift left as many multiples of the block size as possible: if (k >= 32) { result.doShiftBlocksLeft(k >>> 5); } // Shift left by the remaining (<32) amount: final int remaining = k & 0x1f; if (remaining != 0) { for (int i = result.blocks - 1; i >= 1; i--) { result.value[i] <<= remaining; result.value[i] |= result.value[i - 1] >>> (32 - remaining); } result.value[0] <<= remaining; } return result; }
Shifts left b and adds the result to Its a fast version of this = add(b.shl(k));
Params:
  • b – GF2Polynomial to shift and add to this
  • k – the amount to shift
See Also:
/** * Shifts left b and adds the result to Its a fast version of * <tt>this = add(b.shl(k));</tt> * * @param b GF2Polynomial to shift and add to this * @param k the amount to shift * @see GF2nPolynomialElement#invertEEA */
public void shiftLeftAddThis(GF2Polynomial b, int k) { if (k == 0) { addToThis(b); return; } int i; expandN(b.len + k); int d = k >>> 5; for (i = b.blocks - 1; i >= 0; i--) { if ((i + d + 1 < blocks) && ((k & 0x1f) != 0)) { value[i + d + 1] ^= b.value[i] >>> (32 - (k & 0x1f)); } value[i + d] ^= b.value[i] << (k & 0x1f); } }
Shifts-left this GF2Polynomial's value blockwise 1 block resulting in a shift-left by 32.
See Also:
  • multiply.multiply
/** * Shifts-left this GF2Polynomial's value blockwise 1 block resulting in a * shift-left by 32. * * @see GF2Polynomial#multiply */
void shiftBlocksLeft() { blocks += 1; len += 32; if (blocks <= value.length) { int i; for (i = blocks - 1; i >= 1; i--) { value[i] = value[i - 1]; } value[0] = 0x00; } else { int[] result = new int[blocks]; System.arraycopy(value, 0, result, 1, blocks - 1); value = null; value = result; } }
Shifts left this GF2Polynomial's value blockwise b blocks resulting in a shift-left by b*32. This method assumes that len and blocks have already been updated to reflect the final state.
Params:
  • b – shift amount (in blocks)
/** * Shifts left this GF2Polynomial's value blockwise <i>b</i> blocks * resulting in a shift-left by b*32. This method assumes that {@link #len} * and {@link #blocks} have already been updated to reflect the final state. * * @param b shift amount (in blocks) */
private void doShiftBlocksLeft(int b) { if (blocks <= value.length) { int i; for (i = blocks - 1; i >= b; i--) { value[i] = value[i - b]; } for (i = 0; i < b; i++) { value[i] = 0x00; } } else { int[] result = new int[blocks]; System.arraycopy(value, 0, result, b, blocks - b); value = null; value = result; } }
Returns this GF2Polynomial shift-right by 1 in a new GF2Polynomial.
Returns:a new GF2Polynomial (this << 1)
/** * Returns this GF2Polynomial shift-right by 1 in a new GF2Polynomial. * * @return a new GF2Polynomial (this &lt;&lt; 1) */
public GF2Polynomial shiftRight() { GF2Polynomial result = new GF2Polynomial(len - 1); int i; System.arraycopy(value, 0, result.value, 0, result.blocks); for (i = 0; i <= result.blocks - 2; i++) { result.value[i] >>>= 1; result.value[i] |= result.value[i + 1] << 31; } result.value[result.blocks - 1] >>>= 1; if (result.blocks < blocks) { result.value[result.blocks - 1] |= value[result.blocks] << 31; } return result; }
Shifts-right this GF2Polynomial by 1.
/** * Shifts-right this GF2Polynomial by 1. */
public void shiftRightThis() { int i; len -= 1; blocks = ((len - 1) >>> 5) + 1; for (i = 0; i <= blocks - 2; i++) { value[i] >>>= 1; value[i] |= value[i + 1] << 31; } value[blocks - 1] >>>= 1; if ((len & 0x1f) == 0) { value[blocks - 1] |= value[blocks] << 31; } } }