package org.bouncycastle.pqc.math.linearalgebra; /** * This class describes operations with polynomials over finite field GF(2), i e * polynomial ring R = GF(2)[X]. All operations are defined only for polynomials * with degree <=32. For the polynomial representation the map f: R->Z, * poly(X)->poly(2) is used, where integers have the binary representation. For * example: X^7+X^3+X+1 -> (00...0010001011)=139 Also for polynomials type * Integer is used. * * @see GF2mField */ public final class PolynomialRingGF2 { /** * Default constructor (private). */ private PolynomialRingGF2() { // empty } /** * Return sum of two polyomials * * @param p polynomial * @param q polynomial * @return p+q */ public static int add(int p, int q) { return p ^ q; } /** * Return product of two polynomials * * @param p polynomial * @param q polynomial * @return p*q */ public static long multiply(int p, int q) { long result = 0; if (q != 0) { long q1 = q & 0x00000000ffffffffL; while (p != 0) { byte b = (byte)(p & 0x01); if (b == 1) { result ^= q1; } p >>>= 1; q1 <<= 1; } } return result; } /** * Compute the product of two polynomials modulo a third polynomial. * * @param a the first polynomial * @param b the second polynomial * @param r the reduction polynomial * @return <tt>a * b mod r</tt> */ public static int modMultiply(int a, int b, int r) { int result = 0; int p = remainder(a, r); int q = remainder(b, r); if (q != 0) { int d = 1 << degree(r); while (p != 0) { byte pMod2 = (byte)(p & 0x01); if (pMod2 == 1) { result ^= q; } p >>>= 1; q <<= 1; if (q >= d) { q ^= r; } } } return result; } /** * Return the degree of a polynomial * * @param p polynomial p * @return degree(p) */ public static int degree(int p) { int result = -1; while (p != 0) { result++; p >>>= 1; } return result; } /** * Return the degree of a polynomial * * @param p polynomial p * @return degree(p) */ public static int degree(long p) { int result = 0; while (p != 0) { result++; p >>>= 1; } return result - 1; } /** * Return the remainder of a polynomial division of two polynomials. * * @param p dividend * @param q divisor * @return <tt>p mod q</tt> */ public static int remainder(int p, int q) { int result = p; if (q == 0) { System.err.println("Error: to be divided by 0"); return 0; } while (degree(result) >= degree(q)) { result ^= q << (degree(result) - degree(q)); } return result; } /** * Return the rest of devision two polynomials * * @param p polinomial * @param q polinomial * @return p mod q */ public static int rest(long p, int q) { long p1 = p; if (q == 0) { System.err.println("Error: to be divided by 0"); return 0; } long q1 = q & 0x00000000ffffffffL; while ((p1 >>> 32) != 0) { p1 ^= q1 << (degree(p1) - degree(q1)); } int result = (int)(p1 & 0xffffffff); while (degree(result) >= degree(q)) { result ^= q << (degree(result) - degree(q)); } return result; } /** * Return the greatest common divisor of two polynomials * * @param p polinomial * @param q polinomial * @return GCD(p, q) */ public static int gcd(int p, int q) { int a, b, c; a = p; b = q; while (b != 0) { c = remainder(a, b); a = b; b = c; } return a; } /** * Checking polynomial for irreducibility * * @param p polinomial * @return true if p is irreducible and false otherwise */ public static boolean isIrreducible(int p) { if (p == 0) { return false; } int d = degree(p) >>> 1; int u = 2; for (int i = 0; i < d; i++) { u = modMultiply(u, u, p); if (gcd(u ^ 2, p) != 1) { return false; } } return true; } /** * Creates irreducible polynomial with degree d * * @param deg polynomial degree * @return irreducible polynomial p */ public static int getIrreduciblePolynomial(int deg) { if (deg < 0) { System.err.println("The Degree is negative"); return 0; } if (deg > 31) { System.err.println("The Degree is more then 31"); return 0; } if (deg == 0) { return 1; } int a = 1 << deg; a++; int b = 1 << (deg + 1); for (int i = a; i < b; i += 2) { if (isIrreducible(i)) { return i; } } return 0; } }