/// <summary> /// Compute the result of the division of two polynomials over the field <c>GF(2^m)</c> /// </summary> /// /// <param name="A">he first polynomial</param> /// <param name="F">he second polynomial</param> /// /// <returns>Returns <c>int[][] {q,r}</c>, where <c>a = q*f+r</c> and <c>deg(r) < deg(f)</c></returns> private static int[][] Divide(int[] A, int[] F, GF2mField GF2) { int df = ComputeDegree(F); int da = ComputeDegree(A) + 1; if (df == -1) { throw new ArithmeticException("Division by zero."); } int[][] result = new int[2][]; result[0] = new int[1]; result[1] = new int[da]; int hc = HeadCoefficient(F); hc = GF2.Inverse(hc); result[0][0] = 0; Array.Copy(A, 0, result[1], 0, result[1].Length); while (df <= ComputeDegree(result[1])) { int[] q; int[] coeff = new int[1]; coeff[0] = GF2.Multiply(HeadCoefficient(result[1]), hc); q = MultWithElement(F, coeff[0], GF2); int n = ComputeDegree(result[1]) - df; q = MultWithMonomial(q, n); coeff = MultWithMonomial(coeff, n); result[0] = Add(coeff, result[0], GF2); result[1] = Add(q, result[1], GF2); } return(result); }
/// <summary> /// Reduce a polynomial modulo another polynomial /// </summary> /// /// <param name="A">The polynomial</param> /// <param name="F">The reduction polynomial</param> /// /// <returns>Returns <c>a mod f</c></returns> private static int[] Mod(int[] A, int[] F, GF2mField GF2) { int df = ComputeDegree(F); if (df == -1) { throw new ArithmeticException("Division by zero"); } int[] result = new int[A.Length]; int hc = HeadCoefficient(F); hc = GF2.Inverse(hc); Array.Copy(A, 0, result, 0, result.Length); while (df <= ComputeDegree(result)) { int[] q; int coeff = GF2.Multiply(HeadCoefficient(result), hc); q = MultWithMonomial(F, ComputeDegree(result) - df); q = MultWithElement(q, coeff, GF2); result = Add(q, result, GF2); } return(result); }
/// <summary> /// Find an error vector <c>E</c> over <c>GF(2)</c> from an input syndrome <c>S</c> over <c>GF(2^M)</c> /// </summary> /// /// <param name="SyndVec">The syndrome</param> /// <param name="Field">The finite field</param> /// <param name="Gp">The irreducible Goppa polynomial</param> /// <param name="SqRootMatrix">The matrix for computing square roots in <c>(GF(2M))<sup>T</sup></c></param> /// /// <returns>The error vector</returns> public static GF2Vector SyndromeDecode(GF2Vector SyndVec, GF2mField Field, PolynomialGF2mSmallM Gp, PolynomialGF2mSmallM[] SqRootMatrix) { int n = 1 << Field.Degree; // the error vector GF2Vector errors = new GF2Vector(n); // if the syndrome vector is zero, the error vector is also zero if (!SyndVec.IsZero()) { // convert syndrome vector to polynomial over GF(2^m) PolynomialGF2mSmallM syndrome = new PolynomialGF2mSmallM(SyndVec.ToExtensionFieldVector(Field)); // compute T = syndrome^-1 mod gp PolynomialGF2mSmallM t = syndrome.ModInverse(Gp); // compute tau = sqRoot(T + X) mod gp PolynomialGF2mSmallM tau = t.AddMonomial(1); tau = tau.ModSquareRootMatrix(SqRootMatrix); // compute polynomials a and b satisfying a + b*tau = 0 mod gp PolynomialGF2mSmallM[] ab = tau.ModPolynomialToFracton(Gp); // compute the polynomial a^2 + X*b^2 PolynomialGF2mSmallM a2 = ab[0].Multiply(ab[0]); PolynomialGF2mSmallM b2 = ab[1].Multiply(ab[1]); PolynomialGF2mSmallM xb2 = b2.MultWithMonomial(1); PolynomialGF2mSmallM a2plusXb2 = a2.Add(xb2); // normalize a^2 + X*b^2 to obtain the error locator polynomial int headCoeff = a2plusXb2.Head; int invHeadCoeff = Field.Inverse(headCoeff); PolynomialGF2mSmallM elp = a2plusXb2.MultWithElement(invHeadCoeff); // for all elements i of GF(2^m) for (int i = 0; i < n; i++) { // evaluate the error locator polynomial at i int z = elp.EvaluateAt(i); // if polynomial evaluates to zero if (z == 0) { // set the i-th coefficient of the error vector errors.SetBit(i); } } } return(errors); }
/// <summary> /// Return the greatest common divisor of two polynomials over the field <c>GF(2^m)</c> /// </summary> /// /// <param name="F">The first polynomial</param> /// <param name="G">The second polynomial</param> /// /// <returns>Returns <c>Gcd(f, g)</c></returns> private static int[] Gcd(int[] F, int[] G, GF2mField GF2) { int[] a = F; int[] b = G; if (ComputeDegree(a) == -1) { return(b); } while (ComputeDegree(b) != -1) { int[] c = Mod(a, b, GF2); a = new int[b.Length]; Array.Copy(b, 0, a, 0, a.Length); b = new int[c.Length]; Array.Copy(c, 0, b, 0, b.Length); } int coeff = GF2.Inverse(HeadCoefficient(a)); return(MultWithElement(a, coeff, GF2)); }
/// <summary> /// Compute the result of the division of two polynomials modulo a third polynomial over the field <c>GF(2^m)</c> /// </summary> /// /// <param name="A">The first polynomial</param> /// <param name="B">The second polynomial</param> /// <param name="G">The reduction polynomial</param> /// /// <returns>Returns <c>a * b^(-1) mod g</c></returns> private static int[] ModDiv(int[] A, int[] B, int[] G, GF2mField GF2) { int[] r0 = NormalForm(G); int[] r1 = Mod(B, G, GF2); int[] s0 = { 0 }; int[] s1 = Mod(A, G, GF2); int[] s2; int[][] q; while (ComputeDegree(r1) != -1) { q = Divide(r0, r1, GF2); r0 = NormalForm(r1); r1 = NormalForm(q[1]); s2 = Add(s0, ModMultiply(q[0], s1, G, GF2), GF2); s0 = NormalForm(s1); s1 = NormalForm(s2); } int hc = HeadCoefficient(r0); s0 = MultWithElement(s0, GF2.Inverse(hc), GF2); return(s0); }
/// <summary> /// Compute the matrix for computing square roots in this polynomial ring by inverting the squaring matrix /// </summary> private void ComputeSquareRootMatrix() { int numColumns = _poly.Degree; // clone squaring matrix PolynomialGF2mSmallM[] tmpMatrix = new PolynomialGF2mSmallM[numColumns]; for (int i = numColumns - 1; i >= 0; i--) { tmpMatrix[i] = new PolynomialGF2mSmallM(_sqMatrix[i]); } // initialize square root matrix as unit matrix _sqRootMatrix = new PolynomialGF2mSmallM[numColumns]; for (int i = numColumns - 1; i >= 0; i--) { _sqRootMatrix[i] = new PolynomialGF2mSmallM(_field, i); } // simultaneously compute Gaussian reduction of squaring matrix and unit matrix for (int i = 0; i < numColumns; i++) { // if diagonal element is zero if (tmpMatrix[i].GetCoefficient(i) == 0) { bool foundNonZero = false; // find a non-zero element in the same row for (int j = i + 1; j < numColumns; j++) { if (tmpMatrix[j].GetCoefficient(i) != 0) { // found it, swap columns ... foundNonZero = true; SwapColumns(tmpMatrix, i, j); SwapColumns(_sqRootMatrix, i, j); // ... and quit searching j = numColumns; continue; } } // if no non-zero element was found the matrix is not invertible if (!foundNonZero) { throw new ArithmeticException("Squaring matrix is not invertible."); } } // normalize i-th column int coef = tmpMatrix[i].GetCoefficient(i); int invCoef = _field.Inverse(coef); tmpMatrix[i].MultThisWithElement(invCoef); _sqRootMatrix[i].MultThisWithElement(invCoef); if (ParallelUtils.IsParallel) { // normalize all other columns Parallel.For(0, numColumns, j => { if (j != i) { int coefp = tmpMatrix[j].GetCoefficient(i); if (coefp != 0) { PolynomialGF2mSmallM tmpSqColumn = tmpMatrix[i].MultWithElement(coefp); PolynomialGF2mSmallM tmpInvColumn = _sqRootMatrix[i].MultWithElement(coefp); tmpMatrix[j].AddToThis(tmpSqColumn); lock (_sqRootMatrix) _sqRootMatrix[j].AddToThis(tmpInvColumn); } } }); } else { for (int j = 0; j < numColumns; j++) { if (j != i) { coef = tmpMatrix[j].GetCoefficient(i); if (coef != 0) { PolynomialGF2mSmallM tmpSqColumn = tmpMatrix[i].MultWithElement(coef); PolynomialGF2mSmallM tmpInvColumn = _sqRootMatrix[i].MultWithElement(coef); tmpMatrix[j].AddToThis(tmpSqColumn); lock (_sqRootMatrix) _sqRootMatrix[j].AddToThis(tmpInvColumn); } } } } } }
/// <summary> /// Construct the check matrix of a Goppa code in canonical form from the irreducible Goppa polynomial over the finite field <c>GF(2^m)</c>. /// </summary> /// /// <param name="Field">The finite field</param> /// <param name="Gp">The irreducible Goppa polynomial</param> /// /// <returns>The new GF2Matrix</returns> public static GF2Matrix CreateCanonicalCheckMatrix(GF2mField Field, PolynomialGF2mSmallM Gp) { int m = Field.Degree; int n = 1 << m; int t = Gp.Degree; // create matrix H over GF(2^m) int[][] hArray = ArrayUtils.CreateJagged <int[][]>(t, n); // create matrix YZ int[][] yz = ArrayUtils.CreateJagged <int[][]>(t, n); if (ParallelUtils.IsParallel) { Parallel.For(0, n, j => yz[0][j] = Field.Inverse(Gp.EvaluateAt(j))); } else { // here j is used as index and as element of field GF(2^m) for (int j = 0; j < n; j++) { yz[0][j] = Field.Inverse(Gp.EvaluateAt(j)); } } for (int i = 1; i < t; i++) { // here j is used as index and as element of field GF(2^m) if (ParallelUtils.IsParallel) { Parallel.For(0, n, j => { yz[i][j] = Field.Multiply(yz[i - 1][j], j); }); } else { for (int j = 0; j < n; j++) { yz[i][j] = Field.Multiply(yz[i - 1][j], j); } } } // create matrix H = XYZ for (int i = 0; i < t; i++) { if (ParallelUtils.IsParallel) { Parallel.For(0, n, j => { for (int k = 0; k <= i; k++) { hArray[i][j] = Field.Add(hArray[i][j], Field.Multiply(yz[k][j], Gp.GetCoefficient(t + k - i))); } }); } else { for (int j = 0; j < n; j++) { for (int k = 0; k <= i; k++) { hArray[i][j] = Field.Add(hArray[i][j], Field.Multiply(yz[k][j], Gp.GetCoefficient(t + k - i))); } } } } // convert to matrix over GF(2) int[][] result = ArrayUtils.CreateJagged <int[][]>(t * m, IntUtils.URShift((n + 31), 5)); if (ParallelUtils.IsParallel) { for (int j = 0; j < n; j++) { int q = IntUtils.URShift(j, 5); int r = 1 << (j & 0x1f); for (int i = 0; i < t; i++) { int e = hArray[i][j]; Parallel.For(0, m, u => { int b = (IntUtils.URShift(e, u)) & 1; if (b != 0) { int ind = (i + 1) * m - u - 1; result[ind][q] ^= r; } }); } } } else { for (int j = 0; j < n; j++) { int q = IntUtils.URShift(j, 5); int r = 1 << (j & 0x1f); for (int i = 0; i < t; i++) { int e = hArray[i][j]; for (int u = 0; u < m; u++) { int b = (IntUtils.URShift(e, u)) & 1; if (b != 0) { int ind = (i + 1) * m - u - 1; result[ind][q] ^= r; } } } } } return(new GF2Matrix(n, result)); }
/// <summary> /// Reduce a polynomial modulo another polynomial /// </summary> /// /// <param name="A">The polynomial</param> /// <param name="F">The reduction polynomial</param> /// /// <returns>Returns <c>a mod f</c></returns> private static int[] Mod(int[] A, int[] F, GF2mField GF2) { int df = ComputeDegree(F); if (df == -1) throw new ArithmeticException("Division by zero"); int[] result = new int[A.Length]; int hc = HeadCoefficient(F); hc = GF2.Inverse(hc); Array.Copy(A, 0, result, 0, result.Length); while (df <= ComputeDegree(result)) { int[] q; int coeff = GF2.Multiply(HeadCoefficient(result), hc); q = MultWithMonomial(F, ComputeDegree(result) - df); q = MultWithElement(q, coeff, GF2); result = Add(q, result, GF2); } return result; }
/// <summary> /// Compute the result of the division of two polynomials modulo a third polynomial over the field <c>GF(2^m)</c> /// </summary> /// /// <param name="A">The first polynomial</param> /// <param name="B">The second polynomial</param> /// <param name="G">The reduction polynomial</param> /// /// <returns>Returns <c>a * b^(-1) mod g</c></returns> private static int[] ModDiv(int[] A, int[] B, int[] G, GF2mField GF2) { int[] r0 = NormalForm(G); int[] r1 = Mod(B, G, GF2); int[] s0 = { 0 }; int[] s1 = Mod(A, G, GF2); int[] s2; int[][] q; while (ComputeDegree(r1) != -1) { q = Divide(r0, r1, GF2); r0 = NormalForm(r1); r1 = NormalForm(q[1]); s2 = Add(s0, ModMultiply(q[0], s1, G, GF2), GF2); s0 = NormalForm(s1); s1 = NormalForm(s2); } int hc = HeadCoefficient(r0); s0 = MultWithElement(s0, GF2.Inverse(hc), GF2); return s0; }
/// <summary> /// Return the greatest common divisor of two polynomials over the field <c>GF(2^m)</c> /// </summary> /// /// <param name="F">The first polynomial</param> /// <param name="G">The second polynomial</param> /// /// <returns>Returns <c>Gcd(f, g)</c></returns> private static int[] Gcd(int[] F, int[] G, GF2mField GF2) { int[] a = F; int[] b = G; if (ComputeDegree(a) == -1) return b; while (ComputeDegree(b) != -1) { int[] c = Mod(a, b, GF2); a = new int[b.Length]; Array.Copy(b, 0, a, 0, a.Length); b = new int[c.Length]; Array.Copy(c, 0, b, 0, b.Length); } int coeff = GF2.Inverse(HeadCoefficient(a)); return MultWithElement(a, coeff, GF2); }
/// <summary> /// Compute the result of the division of two polynomials over the field <c>GF(2^m)</c> /// </summary> /// /// <param name="A">he first polynomial</param> /// <param name="F">he second polynomial</param> /// /// <returns>Returns <c>int[][] {q,r}</c>, where <c>a = q*f+r</c> and <c>deg(r) < deg(f)</c></returns> private static int[][] Divide(int[] A, int[] F, GF2mField GF2) { int df = ComputeDegree(F); int da = ComputeDegree(A) + 1; if (df == -1) throw new ArithmeticException("Division by zero."); int[][] result = new int[2][]; result[0] = new int[1]; result[1] = new int[da]; int hc = HeadCoefficient(F); hc = GF2.Inverse(hc); result[0][0] = 0; Array.Copy(A, 0, result[1], 0, result[1].Length); while (df <= ComputeDegree(result[1])) { int[] q; int[] coeff = new int[1]; coeff[0] = GF2.Multiply(HeadCoefficient(result[1]), hc); q = MultWithElement(F, coeff[0], GF2); int n = ComputeDegree(result[1]) - df; q = MultWithMonomial(q, n); coeff = MultWithMonomial(coeff, n); result[0] = Add(coeff, result[0], GF2); result[1] = Add(q, result[1], GF2); } return result; }
/// <summary> /// Construct the check matrix of a Goppa code in canonical form from the irreducible Goppa polynomial over the finite field <c>GF(2^m)</c>. /// </summary> /// /// <param name="Field">The finite field</param> /// <param name="Gp">The irreducible Goppa polynomial</param> /// /// <returns>The new GF2Matrix</returns> public static GF2Matrix CreateCanonicalCheckMatrix(GF2mField Field, PolynomialGF2mSmallM Gp) { int m = Field.Degree; int n = 1 << m; int t = Gp.Degree; // create matrix H over GF(2^m) int[][] hArray = ArrayUtils.CreateJagged<int[][]>(t, n); // create matrix YZ int[][] yz = ArrayUtils.CreateJagged<int[][]>(t, n); if (ParallelUtils.IsParallel) { Parallel.For(0, n, j => yz[0][j] = Field.Inverse(Gp.EvaluateAt(j))); } else { // here j is used as index and as element of field GF(2^m) for (int j = 0; j < n; j++) yz[0][j] = Field.Inverse(Gp.EvaluateAt(j)); } for (int i = 1; i < t; i++) { // here j is used as index and as element of field GF(2^m) if (ParallelUtils.IsParallel) { Parallel.For(0, n, j => { yz[i][j] = Field.Multiply(yz[i - 1][j], j); }); } else { for (int j = 0; j < n; j++) yz[i][j] = Field.Multiply(yz[i - 1][j], j); } } // create matrix H = XYZ for (int i = 0; i < t; i++) { if (ParallelUtils.IsParallel) { Parallel.For(0, n, j => { for (int k = 0; k <= i; k++) hArray[i][j] = Field.Add(hArray[i][j], Field.Multiply(yz[k][j], Gp.GetCoefficient(t + k - i))); }); } else { for (int j = 0; j < n; j++) { for (int k = 0; k <= i; k++) hArray[i][j] = Field.Add(hArray[i][j], Field.Multiply(yz[k][j], Gp.GetCoefficient(t + k - i))); } } } // convert to matrix over GF(2) int[][] result = ArrayUtils.CreateJagged<int[][]>(t * m, IntUtils.URShift((n + 31), 5)); if (ParallelUtils.IsParallel) { for (int j = 0; j < n; j++) { int q = IntUtils.URShift(j, 5); int r = 1 << (j & 0x1f); for (int i = 0; i < t; i++) { int e = hArray[i][j]; Parallel.For(0, m, u => { int b = (IntUtils.URShift(e, u)) & 1; if (b != 0) { int ind = (i + 1) * m - u - 1; result[ind][q] ^= r; } }); } } } else { for (int j = 0; j < n; j++) { int q = IntUtils.URShift(j, 5); int r = 1 << (j & 0x1f); for (int i = 0; i < t; i++) { int e = hArray[i][j]; for (int u = 0; u < m; u++) { int b = (IntUtils.URShift(e, u)) & 1; if (b != 0) { int ind = (i + 1) * m - u - 1; result[ind][q] ^= r; } } } } } return new GF2Matrix(n, result); }
/// <summary> /// Find an error vector <c>E</c> over <c>GF(2)</c> from an input syndrome <c>S</c> over <c>GF(2^M)</c> /// </summary> /// /// <param name="SyndVec">The syndrome</param> /// <param name="Field">The finite field</param> /// <param name="Gp">The irreducible Goppa polynomial</param> /// <param name="SqRootMatrix">The matrix for computing square roots in <c>(GF(2M))<sup>T</sup></c></param> /// /// <returns>The error vector</returns> public static GF2Vector SyndromeDecode(GF2Vector SyndVec, GF2mField Field, PolynomialGF2mSmallM Gp, PolynomialGF2mSmallM[] SqRootMatrix) { int n = 1 << Field.Degree; // the error vector GF2Vector errors = new GF2Vector(n); // if the syndrome vector is zero, the error vector is also zero if (!SyndVec.IsZero()) { // convert syndrome vector to polynomial over GF(2^m) PolynomialGF2mSmallM syndrome = new PolynomialGF2mSmallM(SyndVec.ToExtensionFieldVector(Field)); // compute T = syndrome^-1 mod gp PolynomialGF2mSmallM t = syndrome.ModInverse(Gp); // compute tau = sqRoot(T + X) mod gp PolynomialGF2mSmallM tau = t.AddMonomial(1); tau = tau.ModSquareRootMatrix(SqRootMatrix); // compute polynomials a and b satisfying a + b*tau = 0 mod gp PolynomialGF2mSmallM[] ab = tau.ModPolynomialToFracton(Gp); // compute the polynomial a^2 + X*b^2 PolynomialGF2mSmallM a2 = ab[0].Multiply(ab[0]); PolynomialGF2mSmallM b2 = ab[1].Multiply(ab[1]); PolynomialGF2mSmallM xb2 = b2.MultWithMonomial(1); PolynomialGF2mSmallM a2plusXb2 = a2.Add(xb2); // normalize a^2 + X*b^2 to obtain the error locator polynomial int headCoeff = a2plusXb2.Head; int invHeadCoeff = Field.Inverse(headCoeff); PolynomialGF2mSmallM elp = a2plusXb2.MultWithElement(invHeadCoeff); // for all elements i of GF(2^m) for (int i = 0; i < n; i++) { // evaluate the error locator polynomial at i int z = elp.EvaluateAt(i); // if polynomial evaluates to zero if (z == 0) { // set the i-th coefficient of the error vector errors.SetBit(i); } } } return errors; }
/// <summary> /// Compute the inverse of this matrix /// </summary> /// /// <returns>Returns the inverse of this matrix (newly created)</returns> public override Matrix ComputeInverse() { if (RowCount != ColumnCount) { throw new ArithmeticException("GF2mMatrix: Matrix is not invertible!"); } // clone this matrix int[][] tmpMatrix = ArrayUtils.CreateJagged <int[][]>(RowCount, RowCount); for (int i = RowCount - 1; i >= 0; i--) { tmpMatrix[i] = IntUtils.DeepCopy(MatrixN[i]); } // initialize inverse matrix as unit matrix int[][] invMatrix = ArrayUtils.CreateJagged <int[][]>(RowCount, RowCount); for (int i = RowCount - 1; i >= 0; i--) { invMatrix[i][i] = 1; } // simultaneously compute Gaussian reduction of tmpMatrix and unit // matrix for (int i = 0; i < RowCount; i++) { // if diagonal element is zero if (tmpMatrix[i][i] == 0) { bool foundNonZero = false; // find a non-zero element in the same column for (int j = i + 1; j < RowCount; j++) { if (tmpMatrix[j][i] != 0) { // found it, swap rows ... foundNonZero = true; SwapColumns(tmpMatrix, i, j); SwapColumns(invMatrix, i, j); // ... and quit searching j = RowCount; continue; } } // if no non-zero element was found the matrix is not invertible if (!foundNonZero) { throw new ArithmeticException("GF2mMatrix: Matrix is not invertible!"); } } // normalize i-th row int coef = tmpMatrix[i][i]; int invCoef = FieldG.Inverse(coef); MultRowWithElementThis(tmpMatrix[i], invCoef); MultRowWithElementThis(invMatrix[i], invCoef); // normalize all other rows for (int j = 0; j < RowCount; j++) { if (j != i) { coef = tmpMatrix[j][i]; if (coef != 0) { int[] tmpRow = MultRowWithElement(tmpMatrix[i], coef); int[] tmpInvRow = MultRowWithElement(invMatrix[i], coef); AddToRow(tmpRow, tmpMatrix[j]); AddToRow(tmpInvRow, invMatrix[j]); } } } } return(new GF2mMatrix(FieldG, invMatrix)); }