/// <summary> /// Computes a new squaring matrix used for fast squaring /// </summary> private void ComputeSquaringMatrix() { GF2Polynomial[] d = new GF2Polynomial[DegreeN - 1]; int i, j; _squaringMatrix = new GF2Polynomial[DegreeN]; for (i = 0; i < _squaringMatrix.Length; i++) { _squaringMatrix[i] = new GF2Polynomial(DegreeN, "ZERO"); } for (i = 0; i < DegreeN - 1; i++) { d[i] = new GF2Polynomial(1, "ONE").ShiftLeft(DegreeN + i).Remainder(FieldPoly); } for (i = 1; i <= Math.Abs(DegreeN >> 1); i++) { for (j = 1; j <= DegreeN; j++) { if (d[DegreeN - (i << 1)].TestBit(DegreeN - j)) { _squaringMatrix[j - 1].SetBit(DegreeN - i); } } } for (i = Math.Abs(DegreeN >> 1) + 1; i <= DegreeN; i++) { _squaringMatrix[(i << 1) - DegreeN - 1].SetBit(DegreeN - i); } }
/// <summary> /// Creates a new GF2nField of degree <c>i</c> and uses the given <c>G</c> as field polynomial. /// <para>The <c>G</c> is checked whether it is irreducible. This can take some time if <c>Degree</c> is huge!</para> /// </summary> /// /// <param name="Degree">The degree of the GF2nField</param> /// <param name="G">The field polynomial to use</param> public GF2nPolynomialField(int Degree, GF2Polynomial G) { if (Degree < 3) throw new ArgumentException("degree must be at least 3"); if (G.Length != Degree + 1) throw new Exception(); if (!G.IsIrreducible()) throw new Exception(); DegreeN = Degree; // fieldPolynomial = new Bitstring(polynomial); FieldPoly = G; ComputeSquaringMatrix(); int k = 2; // check if the polynomial is a trinomial or pentanomial for (int j = 1; j < FieldPoly.Length - 1; j++) { if (FieldPoly.TestBit(j)) { k++; if (k == 3) _tc = j; if (k <= 5) _pc[k - 3] = j; } } if (k == 3) _isTrinomial = true; if (k == 5) _isPentanomial = true; Fields = new ArrayList(); Matrices = new ArrayList(); }
/// <summary> /// Creates a new GF2nPolynomialElement using the given field and Bitstring /// </summary> /// /// <param name="Gf">The GF2nPolynomialField to use</param> /// <param name="Gp">The desired value as Bitstring</param> public GF2nPolynomialElement(GF2nPolynomialField Gf, GF2Polynomial Gp) { mField = Gf; mDegree = mField.Degree; polynomial = new GF2Polynomial(Gp); polynomial.ExpandN(mDegree); }
/// <summary> /// Creates a new GF2nPolynomialElement using the given field <c>Gf</c> and int[] <c>Is</c> as value /// </summary> /// /// <param name="Gf">The GF2nField to use</param> /// <param name="Is">The integer string to assign to this GF2nPolynomialElement</param> public GF2nPolynomialElement(GF2nPolynomialField Gf, int[] Is) { mField = Gf; mDegree = mField.Degree; polynomial = new GF2Polynomial(mDegree, Is); polynomial.ExpandN(Gf.Degree); }
/// <summary> /// Create a new random GF2nPolynomialElement using the given field and source of randomness /// </summary> /// /// <param name="Gf">The GF2nField to use</param> /// <param name="Rnd">The source of randomness</param> public GF2nPolynomialElement(GF2nPolynomialField Gf, Random Rnd) { mField = Gf; mDegree = mField.Degree; polynomial = new GF2Polynomial(mDegree); Randomize(Rnd); }
/// <summary> /// Creates a new GF2nPolynomialElement using the given field <c>f</c> and byte[] <c>os</c> as value. /// <para>The conversion is done according to 1363.</para> /// </summary> /// /// <param name="Gf">The GF2nField to use</param> /// <param name="Os">The octet string to assign to this GF2nPolynomialElement</param> public GF2nPolynomialElement(GF2nPolynomialField Gf, byte[] Os) { mField = Gf; mDegree = mField.Degree; polynomial = new GF2Polynomial(mDegree, Os); polynomial.ExpandN(mDegree); }
/// <summary> /// Tests all trinomials of degree (n+1) until a irreducible is found and stores the result in <c>field polynomial</c>. /// Returns false if no irreducible trinomial exists in GF(2^n). This can take very long for huge degrees. /// </summary> /// /// <returns>Returns true if an irreducible trinomial is found</returns> private bool TestTrinomials() { int i, l; bool done = false; l = 0; FieldPoly = new GF2Polynomial(DegreeN + 1); FieldPoly.SetBit(0); FieldPoly.SetBit(DegreeN); for (i = 1; (i < DegreeN) && !done; i++) { FieldPoly.SetBit(i); done = FieldPoly.IsIrreducible(); l++; if (done) { _isTrinomial = true; _tc = i; return(done); } FieldPoly.ResetBit(i); done = FieldPoly.IsIrreducible(); } return(done); }
/// <summary> /// Computes the field polynomial for a ONB according to IEEE 1363 A.7.2 /// </summary> protected override void ComputeFieldPolynomial() { if (m_Type == 1) { FieldPoly = new GF2Polynomial(DegreeN + 1, "ALL"); } else if (m_Type == 2) { // 1. q = 1 GF2Polynomial q = new GF2Polynomial(DegreeN + 1, "ONE"); // 2. p = t+1 GF2Polynomial p = new GF2Polynomial(DegreeN + 1, "X"); p.AddToThis(q); GF2Polynomial r; int i; // 3. for i = 1 to (m-1) do for (i = 1; i < DegreeN; i++) { // r <- q r = q; // q <- p q = p; // p = tq+r p = q.ShiftLeft(); p.AddToThis(r); } FieldPoly = p; } }
/// <summary> /// Creates a new PolynomialGF2n from the given Bitstring <c>G</c> over the GF2nField <c>B1</c> /// </summary> /// /// <param name="G">The Bitstring to use</param> /// <param name="B1">The field</param> public GF2nPolynomial(GF2Polynomial G, GF2nField B1) { _size = B1.Degree + 1; _coeff = new GF2nElement[_size]; int i; if (B1 is GF2nONBField) { for (i = 0; i < _size; i++) { if (G.TestBit(i)) _coeff[i] = GF2nONBElement.One((GF2nONBField)B1); else _coeff[i] = GF2nONBElement.Zero((GF2nONBField)B1); } } else if (B1 is GF2nPolynomialField) { for (i = 0; i < _size; i++) { if (G.TestBit(i)) _coeff[i] = GF2nPolynomialElement.One((GF2nPolynomialField)B1); else _coeff[i] = GF2nPolynomialElement.Zero((GF2nPolynomialField)B1); } } else { throw new ArgumentException("GF2nPolynomial: PolynomialGF2n(Bitstring, GF2nField): B1 must be an instance of GF2nONBField or GF2nPolynomialField!"); } }
/// <summary> /// Compute a random root of the given GF2Polynomial /// </summary> /// /// <param name="G">The polynomial</param> /// /// <returns>Returns a random root of <c>G</c></returns> public override GF2nElement RandomRoot(GF2Polynomial G) { // We are in B1!!! GF2nPolynomial c; GF2nPolynomial ut; GF2nElement u; GF2nPolynomial h; int hDegree; // 1. Set g(t) <- f(t) GF2nPolynomial g = new GF2nPolynomial(G, this); int gDegree = g.Degree; int i; // 2. while deg(g) > 1 while (gDegree > 1) { do { // 2.1 choose random u (element of) GF(2^m) u = new GF2nPolynomialElement(this, new Random()); ut = new GF2nPolynomial(2, GF2nPolynomialElement.Zero(this)); // 2.2 Set c(t) <- ut ut.Set(1, u); c = new GF2nPolynomial(ut); // 2.3 For i from 1 to m-1 do for (i = 1; i <= DegreeN - 1; i++) { // 2.3.1 c(t) <- (c(t)^2 + ut) mod g(t) c = c.MultiplyAndReduce(c, g); c = c.Add(ut); } // 2.4 set h(t) <- GCD(c(t), g(t)) h = c.Gcd(g); // 2.5 if h(t) is constant or deg(g) = deg(h) then go to // step 2.1 hDegree = h.Degree; gDegree = g.Degree; }while ((hDegree == 0) || (hDegree == gDegree)); // 2.6 If 2deg(h) > deg(g) then set g(t) <- g(t)/h(t) ... if ((hDegree << 1) > gDegree) { g = g.Quotient(h); } else { g = new GF2nPolynomial(h); // ... else g(t) <- h(t) } gDegree = g.Degree; } // 3. Output g(0) return(g.At(0)); }
/// <summary> /// Squares this GF2nPolynomialElement using GF2nFields squaring matrix. /// <para>This is supposed to be fast when using a polynomial (no tri- or pentanomial) as fieldpolynomial. /// Use SquarePreCalc when using a tri- or pentanomial as fieldpolynomial instead.</para> /// </summary> public void SquareThisMatrix() { GF2Polynomial result = new GF2Polynomial(mDegree); for (int i = 0; i < mDegree; i++) { if (polynomial.VectorMult(((GF2nPolynomialField)mField).SquaringMatrix[mDegree - i - 1])) { result.SetBit(i); } } polynomial = result; }
/// <summary> /// Computes the change-of-basis matrix for basis conversion according to 1363. /// The result is stored in the lists fields and matrices. /// </summary> /// /// <param name="B1">The GF2nField to convert to</param> public override void ComputeCOBMatrix(GF2nField B1) { // we are in B0 here! if (DegreeN != B1.Degree) { throw new ArgumentException("GF2nField.computeCOBMatrix: B1 has a different degree and thus cannot be coverted to!"); } int i, j; GF2nElement[] gamma; GF2nElement u; GF2Polynomial[] COBMatrix = new GF2Polynomial[DegreeN]; for (i = 0; i < DegreeN; i++) { COBMatrix[i] = new GF2Polynomial(DegreeN); } // find Random Root do { // u is in representation according to B1 u = B1.RandomRoot(FieldPoly); }while (u.IsZero()); gamma = new GF2nPolynomialElement[DegreeN]; // build gamma matrix by squaring gamma[0] = (GF2nElement)u.Clone(); for (i = 1; i < DegreeN; i++) { gamma[i] = gamma[i - 1].Square(); } // convert horizontal gamma matrix by vertical Bitstrings for (i = 0; i < DegreeN; i++) { for (j = 0; j < DegreeN; j++) { if (gamma[i].TestBit(j)) { COBMatrix[DegreeN - j - 1].SetBit(DegreeN - i - 1); } } } Fields.Add(B1); Matrices.Add(COBMatrix); B1.Fields.Add(this); B1.Matrices.Add(InvertMatrix(COBMatrix)); }
/// <summary> /// Calculates the multiplicative inverse of <c>this</c> using the modified almost inverse algorithm and returns the result in a new GF2nPolynomialElement /// </summary> /// /// <returns>Returns <c>this</c>^(-1)</returns> public GF2nPolynomialElement InvertMAIA() { if (IsZero()) { throw new ArithmeticException(); } GF2Polynomial b = new GF2Polynomial(mDegree, "ONE"); GF2Polynomial c = new GF2Polynomial(mDegree); GF2Polynomial u = GetGF2Polynomial(); GF2Polynomial v = mField.FieldPolynomial; GF2Polynomial h; while (true) { while (!u.TestBit(0)) { // x|u (x divides u) u.ShiftRightThis(); // u = u / x if (!b.TestBit(0)) { b.ShiftRightThis(); } else { b.AddToThis(mField.FieldPolynomial); b.ShiftRightThis(); } } if (u.IsOne()) { return(new GF2nPolynomialElement((GF2nPolynomialField)mField, b)); } u.ReduceN(); v.ReduceN(); if (u.Length < v.Length) { h = u; u = v; v = h; h = b; b = c; c = h; } u.AddToThis(v); b.AddToThis(c); } }
/// <summary> /// Creates a new GF2nField of degree <c>i</c> and uses the given <c>G</c> as field polynomial. /// <para>The <c>G</c> is checked whether it is irreducible. This can take some time if <c>Degree</c> is huge!</para> /// </summary> /// /// <param name="Degree">The degree of the GF2nField</param> /// <param name="G">The field polynomial to use</param> public GF2nPolynomialField(int Degree, GF2Polynomial G) { if (Degree < 3) { throw new ArgumentException("degree must be at least 3"); } if (G.Length != Degree + 1) { throw new Exception(); } if (!G.IsIrreducible()) { throw new Exception(); } DegreeN = Degree; // fieldPolynomial = new Bitstring(polynomial); FieldPoly = G; ComputeSquaringMatrix(); int k = 2; // check if the polynomial is a trinomial or pentanomial for (int j = 1; j < FieldPoly.Length - 1; j++) { if (FieldPoly.TestBit(j)) { k++; if (k == 3) { _tc = j; } if (k <= 5) { _pc[k - 3] = j; } } } if (k == 3) { _isTrinomial = true; } if (k == 5) { _isPentanomial = true; } Fields = new ArrayList(); Matrices = new ArrayList(); }
/// <summary> /// Calculates the multiplicative inverse of <c>this</c> and returns the result in a new GF2nPolynomialElement /// </summary> /// /// <returns>Returns <c>this</c>^(-1)</returns> public GF2nPolynomialElement InvertEEA() { if (IsZero()) { throw new ArithmeticException(); } GF2Polynomial b = new GF2Polynomial(mDegree + 32, "ONE"); b.ReduceN(); GF2Polynomial c = new GF2Polynomial(mDegree + 32); c.ReduceN(); GF2Polynomial u = GetGF2Polynomial(); GF2Polynomial v = mField.FieldPolynomial; GF2Polynomial h; int j; u.ReduceN(); while (!u.IsOne()) { u.ReduceN(); v.ReduceN(); j = u.Length - v.Length; if (j < 0) { h = u; u = v; v = h; h = b; b = c; c = h; j = -j; c.ReduceN(); // this increases the performance } u.ShiftLeftAddThis(v, j); b.ShiftLeftAddThis(c, j); } b.ReduceN(); return(new GF2nPolynomialElement((GF2nPolynomialField)mField, b)); }
/// <summary> /// Compute <c>this * factor</c> (overwrite <c>this</c>). /// </summary> /// /// <param name="Factor">The factor</param> public override void MultiplyThisBy(IGFElement Factor) { if (!(Factor is GF2nPolynomialElement)) { throw new Exception(); } if (!mField.Equals(((GF2nPolynomialElement)Factor).mField)) { throw new Exception(); } if (Equals(Factor)) { SquareThis(); return; } polynomial = polynomial.Multiply(((GF2nPolynomialElement)Factor).polynomial); ReduceThis(); }
/// <summary> /// Tests all pentanomials of degree (n+1) until a irreducible is found and stores the result in <c>field polynomial</c>. /// Returns false if no irreducible pentanomial exists in GF(2^n). /// This can take very long for huge degrees. /// </summary> /// /// <returns>Returns true if an irreducible pentanomial is found</returns> private bool TestPentanomials() { int i, j, k, l; bool done = false; l = 0; FieldPoly = new GF2Polynomial(DegreeN + 1); FieldPoly.SetBit(0); FieldPoly.SetBit(DegreeN); for (i = 1; (i <= (DegreeN - 3)) && !done; i++) { FieldPoly.SetBit(i); for (j = i + 1; (j <= (DegreeN - 2)) && !done; j++) { FieldPoly.SetBit(j); for (k = j + 1; (k <= (DegreeN - 1)) && !done; k++) { FieldPoly.SetBit(k); if (((DegreeN & 1) != 0) | ((i & 1) != 0) | ((j & 1) != 0) | ((k & 1) != 0)) { done = FieldPoly.IsIrreducible(); l++; if (done) { _isPentanomial = true; _pc[0] = i; _pc[1] = j; _pc[2] = k; return(done); } } FieldPoly.ResetBit(k); } FieldPoly.ResetBit(j); } FieldPoly.ResetBit(i); } return(done); }
/// <summary> /// Creates a new PolynomialGF2n from the given Bitstring <c>G</c> over the GF2nField <c>B1</c> /// </summary> /// /// <param name="G">The Bitstring to use</param> /// <param name="B1">The field</param> public GF2nPolynomial(GF2Polynomial G, GF2nField B1) { _size = B1.Degree + 1; _coeff = new GF2nElement[_size]; int i; if (B1 is GF2nONBField) { for (i = 0; i < _size; i++) { if (G.TestBit(i)) { _coeff[i] = GF2nONBElement.One((GF2nONBField)B1); } else { _coeff[i] = GF2nONBElement.Zero((GF2nONBField)B1); } } } else if (B1 is GF2nPolynomialField) { for (i = 0; i < _size; i++) { if (G.TestBit(i)) { _coeff[i] = GF2nPolynomialElement.One((GF2nPolynomialField)B1); } else { _coeff[i] = GF2nPolynomialElement.Zero((GF2nPolynomialField)B1); } } } else { throw new ArgumentException("GF2nPolynomial: PolynomialGF2n(Bitstring, GF2nField): B1 must be an instance of GF2nONBField or GF2nPolynomialField!"); } }
/// <summary> /// Tests random polynomials of degree (n+1) until an irreducible is found and stores the result in <c>field polynomial</c>. /// This can take very long for huge degrees. /// </summary> /// /// <returns>Returns true</returns> private bool TestRandom() { int l; bool done = false; FieldPoly = new GF2Polynomial(DegreeN + 1); l = 0; while (!done) { l++; FieldPoly.Randomize(); FieldPoly.SetBit(DegreeN); FieldPoly.SetBit(0); if (FieldPoly.IsIrreducible()) { done = true; return(done); } } return(done); }
/// <summary> /// Inverts the given matrix represented as bitstrings /// </summary> /// /// <param name="MatrixN">The matrix to invert as a Bitstring[]</param> /// /// <returns>Returns <c>matrix^(-1)</c></returns> protected GF2Polynomial[] InvertMatrix(GF2Polynomial[] MatrixN) { GF2Polynomial[] a = new GF2Polynomial[MatrixN.Length]; GF2Polynomial[] inv = new GF2Polynomial[MatrixN.Length]; GF2Polynomial dummy; int i, j; // initialize a as a copy of matrix and inv as E(inheitsmatrix) for (i = 0; i < DegreeN; i++) { try { a[i] = new GF2Polynomial(MatrixN[i]); inv[i] = new GF2Polynomial(DegreeN); inv[i].SetBit(DegreeN - 1 - i); } catch { throw; } } // construct triangle matrix so that for each a[i] the first i bits are // zero for (i = 0; i < DegreeN - 1; i++) { // find column where bit i is set j = i; while ((j < DegreeN) && !a[j].TestBit(DegreeN - 1 - i)) j++; if (j >= DegreeN) throw new Exception("GF2nField.InvertMatrix: Matrix cannot be inverted!"); if (i != j) { // swap a[i]/a[j] and inv[i]/inv[j] dummy = a[i]; a[i] = a[j]; a[j] = dummy; dummy = inv[i]; inv[i] = inv[j]; inv[j] = dummy; } for (j = i + 1; j < DegreeN; j++) { // add column i to all columns>i // having their i-th bit set if (a[j].TestBit(DegreeN - 1 - i)) { a[j].AddToThis(a[i]); inv[j].AddToThis(inv[i]); } } } // construct Einheitsmatrix from a for (i = DegreeN - 1; i > 0; i--) { for (j = i - 1; j >= 0; j--) { // eliminate the i-th bit in all // columns < i if (a[j].TestBit(DegreeN - 1 - i)) { a[j].AddToThis(a[i]); inv[j].AddToThis(inv[i]); } } } return inv; }
/// <summary> /// Tests all trinomials of degree (n+1) until a irreducible is found and stores the result in <c>field polynomial</c>. /// Returns false if no irreducible trinomial exists in GF(2^n). This can take very long for huge degrees. /// </summary> /// /// <returns>Returns true if an irreducible trinomial is found</returns> private bool TestTrinomials() { int i, l; bool done = false; l = 0; FieldPoly = new GF2Polynomial(DegreeN + 1); FieldPoly.SetBit(0); FieldPoly.SetBit(DegreeN); for (i = 1; (i < DegreeN) && !done; i++) { FieldPoly.SetBit(i); done = FieldPoly.IsIrreducible(); l++; if (done) { _isTrinomial = true; _tc = i; return done; } FieldPoly.ResetBit(i); done = FieldPoly.IsIrreducible(); } return done; }
/// <summary> /// Tests all pentanomials of degree (n+1) until a irreducible is found and stores the result in <c>field polynomial</c>. /// Returns false if no irreducible pentanomial exists in GF(2^n). /// This can take very long for huge degrees. /// </summary> /// /// <returns>Returns true if an irreducible pentanomial is found</returns> private bool TestPentanomials() { int i, j, k, l; bool done = false; l = 0; FieldPoly = new GF2Polynomial(DegreeN + 1); FieldPoly.SetBit(0); FieldPoly.SetBit(DegreeN); for (i = 1; (i <= (DegreeN - 3)) && !done; i++) { FieldPoly.SetBit(i); for (j = i + 1; (j <= (DegreeN - 2)) && !done; j++) { FieldPoly.SetBit(j); for (k = j + 1; (k <= (DegreeN - 1)) && !done; k++) { FieldPoly.SetBit(k); if (((DegreeN & 1) != 0) | ((i & 1) != 0) | ((j & 1) != 0) | ((k & 1) != 0)) { done = FieldPoly.IsIrreducible(); l++; if (done) { _isPentanomial = true; _pc[0] = i; _pc[1] = j; _pc[2] = k; return done; } } FieldPoly.ResetBit(k); } FieldPoly.ResetBit(j); } FieldPoly.ResetBit(i); } return done; }
/// <summary> /// Compute a random root of the given GF2Polynomial /// </summary> /// /// <param name="G">The polynomial</param> /// /// <returns>Returns a random root of <c>G</c></returns> public override GF2nElement RandomRoot(GF2Polynomial G) { // We are in B1!!! GF2nPolynomial c; GF2nPolynomial ut; GF2nElement u; GF2nPolynomial h; int hDegree; // 1. Set g(t) <- f(t) GF2nPolynomial g = new GF2nPolynomial(G, this); int gDegree = g.Degree; int i; // 2. while deg(g) > 1 while (gDegree > 1) { do { // 2.1 choose random u (element of) GF(2^m) u = new GF2nPolynomialElement(this, new Random()); ut = new GF2nPolynomial(2, GF2nPolynomialElement.Zero(this)); // 2.2 Set c(t) <- ut ut.Set(1, u); c = new GF2nPolynomial(ut); // 2.3 For i from 1 to m-1 do for (i = 1; i <= DegreeN - 1; i++) { // 2.3.1 c(t) <- (c(t)^2 + ut) mod g(t) c = c.MultiplyAndReduce(c, g); c = c.Add(ut); } // 2.4 set h(t) <- GCD(c(t), g(t)) h = c.Gcd(g); // 2.5 if h(t) is constant or deg(g) = deg(h) then go to // step 2.1 hDegree = h.Degree; gDegree = g.Degree; } while ((hDegree == 0) || (hDegree == gDegree)); // 2.6 If 2deg(h) > deg(g) then set g(t) <- g(t)/h(t) ... if ((hDegree << 1) > gDegree) g = g.Quotient(h); else g = new GF2nPolynomial(h); // ... else g(t) <- h(t) gDegree = g.Degree; } // 3. Output g(0) return g.At(0); }
/** * . * * @param other t */ /// <summary> /// Creates a new GF2nPolynomialElement by cloning the given GF2nPolynomialElement <c>Ge</c> /// </summary> /// /// <param name="Ge">The GF2nPolynomialElement to clone</param> public GF2nPolynomialElement(GF2nPolynomialElement Ge) { mField = Ge.mField; mDegree = Ge.mDegree; polynomial = new GF2Polynomial(Ge.polynomial); }
/// <summary> /// Create the one element /// </summary> /// /// <param name="Gf">The finite field</param> /// /// <returns>The one element in the given finite field</returns> public static GF2nPolynomialElement One(GF2nPolynomialField Gf) { GF2Polynomial polynomial = new GF2Polynomial(Gf.Degree, new int[] { 1 }); return(new GF2nPolynomialElement(Gf, polynomial)); }
/// <summary> /// Computes a random root from the given irreducible fieldpolynomial according to IEEE 1363 algorithm A.5.6. /// <para>This calculation take very long for big degrees.</para> /// </summary> /// /// <param name="B0FieldPolynomial">The fieldpolynomial if the other basis as a Bitstring</param> /// /// <returns>Returns a random root of BOFieldPolynomial in representation according to this field</returns> public abstract GF2nElement RandomRoot(GF2Polynomial B0FieldPolynomial);
/// <summary> /// Inverts the given matrix represented as bitstrings /// </summary> /// /// <param name="MatrixN">The matrix to invert as a Bitstring[]</param> /// /// <returns>Returns <c>matrix^(-1)</c></returns> protected GF2Polynomial[] InvertMatrix(GF2Polynomial[] MatrixN) { GF2Polynomial[] a = new GF2Polynomial[MatrixN.Length]; GF2Polynomial[] inv = new GF2Polynomial[MatrixN.Length]; GF2Polynomial dummy; int i, j; // initialize a as a copy of matrix and inv as E(inheitsmatrix) for (i = 0; i < DegreeN; i++) { try { a[i] = new GF2Polynomial(MatrixN[i]); inv[i] = new GF2Polynomial(DegreeN); inv[i].SetBit(DegreeN - 1 - i); } catch { throw; } } // construct triangle matrix so that for each a[i] the first i bits are // zero for (i = 0; i < DegreeN - 1; i++) { // find column where bit i is set j = i; while ((j < DegreeN) && !a[j].TestBit(DegreeN - 1 - i)) { j++; } if (j >= DegreeN) { throw new Exception("GF2nField.InvertMatrix: Matrix cannot be inverted!"); } if (i != j) { // swap a[i]/a[j] and inv[i]/inv[j] dummy = a[i]; a[i] = a[j]; a[j] = dummy; dummy = inv[i]; inv[i] = inv[j]; inv[j] = dummy; } for (j = i + 1; j < DegreeN; j++) { // add column i to all columns>i // having their i-th bit set if (a[j].TestBit(DegreeN - 1 - i)) { a[j].AddToThis(a[i]); inv[j].AddToThis(inv[i]); } } } // construct Einheitsmatrix from a for (i = DegreeN - 1; i > 0; i--) { for (j = i - 1; j >= 0; j--) { // eliminate the i-th bit in all // columns < i if (a[j].TestBit(DegreeN - 1 - i)) { a[j].AddToThis(a[i]); inv[j].AddToThis(inv[i]); } } } return(inv); }
/// <summary> /// Converts the given element in representation according to this field to a new element in /// representation according to B1 using the change-of-basis matrix calculated by computeCOBMatrix. /// </summary> /// /// <param name="Elem">The GF2nElement to convert</param> /// <param name="Basis">The basis to convert <c>Elem</c> to</param> /// /// <returns>Returns <c>Elem</c> converted to a new element representation according to <c>basis</c></returns> public GF2nElement Convert(GF2nElement Elem, GF2nField Basis) { if (Basis == this) { return((GF2nElement)Elem.Clone()); } if (FieldPoly.Equals(Basis.FieldPoly)) { return((GF2nElement)Elem.Clone()); } if (DegreeN != Basis.DegreeN) { throw new Exception("GF2nField.Convert: B1 has a different degree and thus cannot be coverted to!"); } int i; GF2Polynomial[] COBMatrix; i = Fields.IndexOf(Basis); if (i == -1) { ComputeCOBMatrix(Basis); i = Fields.IndexOf(Basis); } COBMatrix = (GF2Polynomial[])Matrices[i]; GF2nElement elemCopy = (GF2nElement)Elem.Clone(); if (elemCopy is GF2nONBElement) { ((GF2nONBElement)elemCopy).ReverseOrder(); } GF2Polynomial bs = new GF2Polynomial(DegreeN, elemCopy.ToFlexiBigInt()); bs.ExpandN(DegreeN); GF2Polynomial result = new GF2Polynomial(DegreeN); for (i = 0; i < DegreeN; i++) { if (bs.VectorMult(COBMatrix[i])) { result.SetBit(DegreeN - 1 - i); } } if (Basis is GF2nPolynomialField) { return(new GF2nPolynomialElement((GF2nPolynomialField)Basis, result)); } else if (Basis is GF2nONBField) { GF2nONBElement res = new GF2nONBElement((GF2nONBField)Basis, result.ToFlexiBigInt()); res.ReverseOrder(); return(res); } else { throw new Exception("GF2nField.convert: B1 must be an instance of GF2nPolynomialField or GF2nONBField!"); } }
/// <summary> /// Computes the change-of-basis matrix for basis conversion according to 1363. /// The result is stored in the lists fields and matrices. /// </summary> /// /// <param name="B1">The GF2nField to convert to</param> public override void ComputeCOBMatrix(GF2nField B1) { // we are in B0 here! if (DegreeN != B1.Degree) throw new ArgumentException("GF2nField.computeCOBMatrix: B1 has a different degree and thus cannot be coverted to!"); int i, j; GF2nElement[] gamma; GF2nElement u; GF2Polynomial[] COBMatrix = new GF2Polynomial[DegreeN]; for (i = 0; i < DegreeN; i++) COBMatrix[i] = new GF2Polynomial(DegreeN); // find Random Root do { // u is in representation according to B1 u = B1.RandomRoot(FieldPoly); } while (u.IsZero()); gamma = new GF2nPolynomialElement[DegreeN]; // build gamma matrix by squaring gamma[0] = (GF2nElement)u.Clone(); for (i = 1; i < DegreeN; i++) gamma[i] = gamma[i - 1].Square(); // convert horizontal gamma matrix by vertical Bitstrings for (i = 0; i < DegreeN; i++) { for (j = 0; j < DegreeN; j++) { if (gamma[i].TestBit(j)) COBMatrix[DegreeN - j - 1].SetBit(DegreeN - i - 1); } } Fields.Add(B1); Matrices.Add(COBMatrix); B1.Fields.Add(this); B1.Matrices.Add(InvertMatrix(COBMatrix)); }
/// <summary> /// Computes the change-of-basis matrix for basis conversion according to 1363. /// The result is stored in the lists fields and matrices. /// </summary> /// /// <param name="B1">The GF2nField to convert to</param> public override void ComputeCOBMatrix(GF2nField B1) { // we are in B0 here! if (DegreeN != B1.Degree) { throw new ArgumentException("GF2nPolynomialField.computeCOBMatrix: B1 has a different degree and thus cannot be coverted to!"); } if (B1 is GF2nONBField) { // speedup (calculation is done in PolynomialElements instead of ONB) B1.ComputeCOBMatrix(this); return; } int i, j; GF2nElement[] gamma; GF2nElement u; GF2Polynomial[] COBMatrix = new GF2Polynomial[DegreeN]; for (i = 0; i < DegreeN; i++) { COBMatrix[i] = new GF2Polynomial(DegreeN); } // find Random Root do { // u is in representation according to B1 u = B1.RandomRoot(FieldPoly); }while (u.IsZero()); // build gamma matrix by multiplying by u if (u is GF2nONBElement) { gamma = new GF2nONBElement[DegreeN]; gamma[DegreeN - 1] = GF2nONBElement.One((GF2nONBField)B1); } else { gamma = new GF2nPolynomialElement[DegreeN]; gamma[DegreeN - 1] = GF2nPolynomialElement.One((GF2nPolynomialField)B1); } gamma[DegreeN - 2] = u; for (i = DegreeN - 3; i >= 0; i--) { gamma[i] = (GF2nElement)gamma[i + 1].Multiply(u); } if (B1 is GF2nONBField) { // convert horizontal gamma matrix by vertical Bitstrings for (i = 0; i < DegreeN; i++) { for (j = 0; j < DegreeN; j++) { // TODO remember: ONB treats its Bits in reverse order !!! if (gamma[i].TestBit(DegreeN - j - 1)) { COBMatrix[DegreeN - j - 1].SetBit(DegreeN - i - 1); } } } } else { // convert horizontal gamma matrix by vertical Bitstrings for (i = 0; i < DegreeN; i++) { for (j = 0; j < DegreeN; j++) { if (gamma[i].TestBit(j)) { COBMatrix[DegreeN - j - 1].SetBit(DegreeN - i - 1); } } } } // store field and matrix for further use Fields.Add(B1); Matrices.Add(COBMatrix); // store field and inverse matrix for further use in B1 B1.Fields.Add(this); B1.Matrices.Add(InvertMatrix(COBMatrix)); }
/// <summary> /// Squares this GF2nPolynomialElement using GF2nFields squaring matrix. /// <para>This is supposed to be fast when using a polynomial (no tri- or pentanomial) as fieldpolynomial. /// Use SquarePreCalc when using a tri- or pentanomial as fieldpolynomial instead.</para> /// </summary> public void SquareThisMatrix() { GF2Polynomial result = new GF2Polynomial(mDegree); for (int i = 0; i < mDegree; i++) { if (polynomial.VectorMult(((GF2nPolynomialField)mField).SquaringMatrix[mDegree - i - 1])) result.SetBit(i); } polynomial = result; }
/// <summary> /// Create the one element /// </summary> /// /// <param name="Gf">The finite field</param> /// /// <returns>The one element in the given finite field</returns> public static GF2nPolynomialElement One(GF2nPolynomialField Gf) { GF2Polynomial polynomial = new GF2Polynomial(Gf.Degree, new int[] { 1 }); return new GF2nPolynomialElement(Gf, polynomial); }
/// <summary> /// Create the zero element /// </summary> /// /// <param name="Gf">The finite field</param> /// /// <returns>The zero element in the given finite field</returns> public static GF2nPolynomialElement Zero(GF2nPolynomialField Gf) { GF2Polynomial polynomial = new GF2Polynomial(Gf.Degree); return(new GF2nPolynomialElement(Gf, polynomial)); }
/// <summary> /// Create the zero element /// </summary> /// /// <param name="Gf">The finite field</param> /// /// <returns>The zero element in the given finite field</returns> public static GF2nPolynomialElement Zero(GF2nPolynomialField Gf) { GF2Polynomial polynomial = new GF2Polynomial(Gf.Degree); return new GF2nPolynomialElement(Gf, polynomial); }
/// <summary> /// Reduces this GF2nPolynomialElement modulo the field-polynomial /// </summary> private void ReduceThis() { if (polynomial.Length > mDegree) { // really reduce ? if (((GF2nPolynomialField)mField).IsTrinomial) { // fieldpolonomial // is trinomial int tc; try { tc = ((GF2nPolynomialField)mField).Tc; } catch (Exception NATExc) { throw new Exception("GF2nPolynomialElement.Reduce: the field polynomial is not a trinomial!", NATExc); } // do we have to use slow bitwise reduction ? if (((mDegree - tc) <= 32) || (polynomial.Length > (mDegree << 1))) { ReduceTrinomialBitwise(tc); return; } polynomial.ReduceTrinomial(mDegree, tc); return; } else if (((GF2nPolynomialField)mField).IsPentanomial) // fieldpolynomial is pentanomial { int[] pc; try { pc = ((GF2nPolynomialField)mField).Pc; } catch (Exception NATExc) { throw new Exception("GF2nPolynomialElement.Reduce: the field polynomial is not a pentanomial!", NATExc); } // do we have to use slow bitwise reduction ? if (((mDegree - pc[2]) <= 32) || (polynomial.Length > (mDegree << 1))) { ReducePentanomialBitwise(pc); return; } polynomial.ReducePentanomial(mDegree, pc); return; } else { // fieldpolynomial is something else polynomial = polynomial.Remainder(mField.FieldPolynomial); polynomial.ExpandN(mDegree); return; } } if (polynomial.Length < mDegree) polynomial.ExpandN(mDegree); }
/// <summary> /// Calculates the multiplicative inverse of <c>this</c> and returns the result in a new GF2nPolynomialElement /// </summary> /// /// <returns>Returns <c>this</c>^(-1)</returns> public GF2nPolynomialElement InvertEEA() { if (IsZero()) throw new ArithmeticException(); GF2Polynomial b = new GF2Polynomial(mDegree + 32, "ONE"); b.ReduceN(); GF2Polynomial c = new GF2Polynomial(mDegree + 32); c.ReduceN(); GF2Polynomial u = GetGF2Polynomial(); GF2Polynomial v = mField.FieldPolynomial; GF2Polynomial h; int j; u.ReduceN(); while (!u.IsOne()) { u.ReduceN(); v.ReduceN(); j = u.Length - v.Length; if (j < 0) { h = u; u = v; v = h; h = b; b = c; c = h; j = -j; c.ReduceN(); // this increases the performance } u.ShiftLeftAddThis(v, j); b.ShiftLeftAddThis(c, j); } b.ReduceN(); return new GF2nPolynomialElement((GF2nPolynomialField)mField, b); }
/** * . * * @param other t */ /// <summary> /// Creates a new GF2nPolynomialElement by cloning the given GF2nPolynomialElement <c>Ge</c> /// </summary> /// /// <param name="Ge">The GF2nPolynomialElement to clone</param> public GF2nPolynomialElement(GF2nPolynomialElement Ge) { m_Field = Ge.m_Field; m_Degree = Ge.m_Degree; m_polynomial = new GF2Polynomial(Ge.m_polynomial); }
/// <summary> /// Calculates the multiplicative inverse of <c>this</c> using the modified almost inverse algorithm and returns the result in a new GF2nPolynomialElement /// </summary> /// /// <returns>Returns <c>this</c>^(-1)</returns> public GF2nPolynomialElement InvertMAIA() { if (IsZero()) { throw new ArithmeticException(); } GF2Polynomial b = new GF2Polynomial(mDegree, "ONE"); GF2Polynomial c = new GF2Polynomial(mDegree); GF2Polynomial u = GetGF2Polynomial(); GF2Polynomial v = mField.FieldPolynomial; GF2Polynomial h; while (true) { while (!u.TestBit(0)) { // x|u (x divides u) u.ShiftRightThis(); // u = u / x if (!b.TestBit(0)) { b.ShiftRightThis(); } else { b.AddToThis(mField.FieldPolynomial); b.ShiftRightThis(); } } if (u.IsOne()) return new GF2nPolynomialElement((GF2nPolynomialField)mField, b); u.ReduceN(); v.ReduceN(); if (u.Length < v.Length) { h = u; u = v; v = h; h = b; b = c; c = h; } u.AddToThis(v); b.AddToThis(c); } }
/// <summary> /// Computes the change-of-basis matrix for basis conversion according to 1363. /// The result is stored in the lists fields and matrices. /// </summary> /// /// <param name="B1">The GF2nField to convert to</param> public override void ComputeCOBMatrix(GF2nField B1) { // we are in B0 here! if (DegreeN != B1.Degree) throw new ArgumentException("GF2nPolynomialField.computeCOBMatrix: B1 has a different degree and thus cannot be coverted to!"); if (B1 is GF2nONBField) { // speedup (calculation is done in PolynomialElements instead of ONB) B1.ComputeCOBMatrix(this); return; } int i, j; GF2nElement[] gamma; GF2nElement u; GF2Polynomial[] COBMatrix = new GF2Polynomial[DegreeN]; for (i = 0; i < DegreeN; i++) COBMatrix[i] = new GF2Polynomial(DegreeN); // find Random Root do { // u is in representation according to B1 u = B1.RandomRoot(FieldPoly); } while (u.IsZero()); // build gamma matrix by multiplying by u if (u is GF2nONBElement) { gamma = new GF2nONBElement[DegreeN]; gamma[DegreeN - 1] = GF2nONBElement.One((GF2nONBField)B1); } else { gamma = new GF2nPolynomialElement[DegreeN]; gamma[DegreeN - 1] = GF2nPolynomialElement.One((GF2nPolynomialField)B1); } gamma[DegreeN - 2] = u; for (i = DegreeN - 3; i >= 0; i--) gamma[i] = (GF2nElement)gamma[i + 1].Multiply(u); if (B1 is GF2nONBField) { // convert horizontal gamma matrix by vertical Bitstrings for (i = 0; i < DegreeN; i++) { for (j = 0; j < DegreeN; j++) { // TODO remember: ONB treats its Bits in reverse order !!! if (gamma[i].TestBit(DegreeN - j - 1)) COBMatrix[DegreeN - j - 1].SetBit(DegreeN - i - 1); } } } else { // convert horizontal gamma matrix by vertical Bitstrings for (i = 0; i < DegreeN; i++) { for (j = 0; j < DegreeN; j++) { if (gamma[i].TestBit(j)) COBMatrix[DegreeN - j - 1].SetBit(DegreeN - i - 1); } } } // store field and matrix for further use Fields.Add(B1); Matrices.Add(COBMatrix); // store field and inverse matrix for further use in B1 B1.Fields.Add(this); B1.Matrices.Add(InvertMatrix(COBMatrix)); }
/// <summary> /// Computes a new squaring matrix used for fast squaring /// </summary> private void ComputeSquaringMatrix() { GF2Polynomial[] d = new GF2Polynomial[DegreeN - 1]; int i, j; _squaringMatrix = new GF2Polynomial[DegreeN]; for (i = 0; i < _squaringMatrix.Length; i++) _squaringMatrix[i] = new GF2Polynomial(DegreeN, "ZERO"); for (i = 0; i < DegreeN - 1; i++) d[i] = new GF2Polynomial(1, "ONE").ShiftLeft(DegreeN + i).Remainder(FieldPoly); for (i = 1; i <= Math.Abs(DegreeN >> 1); i++) { for (j = 1; j <= DegreeN; j++) { if (d[DegreeN - (i << 1)].TestBit(DegreeN - j)) _squaringMatrix[j - 1].SetBit(DegreeN - i); } } for (i = Math.Abs(DegreeN >> 1) + 1; i <= DegreeN; i++) _squaringMatrix[(i << 1) - DegreeN - 1].SetBit(DegreeN - i); }
/// <summary> /// Compute <c>this * factor</c> (overwrite <c>this</c>). /// </summary> /// /// <param name="Factor">The factor</param> public override void MultiplyThisBy(IGFElement Factor) { if (!(Factor is GF2nPolynomialElement)) throw new Exception(); if (!mField.Equals(((GF2nPolynomialElement)Factor).mField)) throw new Exception(); if (Equals(Factor)) { SquareThis(); return; } polynomial = polynomial.Multiply(((GF2nPolynomialElement)Factor).polynomial); ReduceThis(); }
/// <summary> /// Tests random polynomials of degree (n+1) until an irreducible is found and stores the result in <c>field polynomial</c>. /// This can take very long for huge degrees. /// </summary> /// /// <returns>Returns true</returns> private bool TestRandom() { int l; bool done = false; FieldPoly = new GF2Polynomial(DegreeN + 1); l = 0; while (!done) { l++; FieldPoly.Randomize(); FieldPoly.SetBit(DegreeN); FieldPoly.SetBit(0); if (FieldPoly.IsIrreducible()) { done = true; return done; } } return done; }
/// <summary> /// Reduces this GF2nPolynomialElement modulo the field-polynomial /// </summary> private void ReduceThis() { if (polynomial.Length > mDegree) { // really reduce ? if (((GF2nPolynomialField)mField).IsTrinomial) { // fieldpolonomial // is trinomial int tc; try { tc = ((GF2nPolynomialField)mField).Tc; } catch (Exception NATExc) { throw new Exception("GF2nPolynomialElement.Reduce: the field polynomial is not a trinomial!"); } // do we have to use slow bitwise reduction ? if (((mDegree - tc) <= 32) || (polynomial.Length > (mDegree << 1))) { ReduceTrinomialBitwise(tc); return; } polynomial.ReduceTrinomial(mDegree, tc); return; } else if (((GF2nPolynomialField)mField).IsPentanomial) // fieldpolynomial is pentanomial { int[] pc; try { pc = ((GF2nPolynomialField)mField).Pc; } catch (Exception NATExc) { throw new Exception("GF2nPolynomialElement.Reduce: the field polynomial is not a pentanomial!"); } // do we have to use slow bitwise reduction ? if (((mDegree - pc[2]) <= 32) || (polynomial.Length > (mDegree << 1))) { ReducePentanomialBitwise(pc); return; } polynomial.ReducePentanomial(mDegree, pc); return; } else { // fieldpolynomial is something else polynomial = polynomial.Remainder(mField.FieldPolynomial); polynomial.ExpandN(mDegree); return; } } if (polynomial.Length < mDegree) { polynomial.ExpandN(mDegree); } }
/// <summary> /// Computes the field polynomial for a ONB according to IEEE 1363 A.7.2 /// </summary> protected override void ComputeFieldPolynomial() { if (_mType == 1) { FieldPoly = new GF2Polynomial(DegreeN + 1, "ALL"); } else if (_mType == 2) { // 1. q = 1 GF2Polynomial q = new GF2Polynomial(DegreeN + 1, "ONE"); // 2. p = t+1 GF2Polynomial p = new GF2Polynomial(DegreeN + 1, "X"); p.AddToThis(q); GF2Polynomial r; int i; // 3. for i = 1 to (m-1) do for (i = 1; i < DegreeN; i++) { // r <- q r = q; // q <- p q = p; // p = tq+r p = q.ShiftLeft(); p.AddToThis(r); } FieldPoly = p; } }
/// <summary> /// Converts the given element in representation according to this field to a new element in /// representation according to B1 using the change-of-basis matrix calculated by computeCOBMatrix. /// </summary> /// /// <param name="Elem">The GF2nElement to convert</param> /// <param name="Basis">The basis to convert <c>Elem</c> to</param> /// /// <returns>Returns <c>Elem</c> converted to a new element representation according to <c>basis</c></returns> public GF2nElement Convert(GF2nElement Elem, GF2nField Basis) { if (Basis == this) return (GF2nElement)Elem.Clone(); if (FieldPoly.Equals(Basis.FieldPoly)) return (GF2nElement)Elem.Clone(); if (DegreeN != Basis.DegreeN) throw new Exception("GF2nField.Convert: B1 has a different degree and thus cannot be coverted to!"); int i; GF2Polynomial[] COBMatrix; i = Fields.IndexOf(Basis); if (i == -1) { ComputeCOBMatrix(Basis); i = Fields.IndexOf(Basis); } COBMatrix = (GF2Polynomial[])Matrices[i]; GF2nElement elemCopy = (GF2nElement)Elem.Clone(); if (elemCopy is GF2nONBElement) ((GF2nONBElement)elemCopy).ReverseOrder(); GF2Polynomial bs = new GF2Polynomial(DegreeN, elemCopy.ToFlexiBigInt()); bs.ExpandN(DegreeN); GF2Polynomial result = new GF2Polynomial(DegreeN); for (i = 0; i < DegreeN; i++) { if (bs.VectorMult(COBMatrix[i])) result.SetBit(DegreeN - 1 - i); } if (Basis is GF2nPolynomialField) { return new GF2nPolynomialElement((GF2nPolynomialField)Basis, result); } else if (Basis is GF2nONBField) { GF2nONBElement res = new GF2nONBElement((GF2nONBField)Basis, result.ToFlexiBigInt()); res.ReverseOrder(); return res; } else { throw new Exception("GF2nField.convert: B1 must be an instance of GF2nPolynomialField or GF2nONBField!"); } }