/// <summary> /// This function uses backward substitution to find x of the linear equation system (LES) B*x = b, /// where A a triangle-matrix is (contains only zeros under the diagonal) and b is a vector. /// <para>If the multiplicative inverse of 0 is needed, an exception is thrown. /// In this case is the LES not solvable.</para> /// </summary> /// /// <exception cref="ArgumentException">Thrown if a multiplicative inverse of 0 is needed</exception> private void Substitute() { // for the temporary results of the operations in field short tmp, temp; temp = GF2Field.InvElem(_A[_A.Length - 1][_A.Length - 1]); if (temp == 0) { throw new CryptoAsymmetricSignException("ComputeInField:Substitute", "The equation system is not solvable!", new ArgumentException()); } // backward substitution _X[_A.Length - 1] = GF2Field.MultElem(_A[_A.Length - 1][_A.Length], temp); for (int i = _A.Length - 2; i >= 0; i--) { tmp = _A[i][_A.Length]; for (int j = _A.Length - 1; j > i; j--) { temp = GF2Field.MultElem(_A[i][j], _X[j]); tmp = GF2Field.AddElem(tmp, temp); } temp = GF2Field.InvElem(_A[i][i]); if (temp == 0) { throw new CryptoAsymmetricSignException("ComputeInField:Substitute", "Not a solvable equation system!", new ArgumentException()); } _X[i] = GF2Field.MultElem(tmp, temp); } }
/// <summary> /// Elimination above the diagonal. /// <para>This function changes a matrix so that it contains only zeros above the diagonal(Ai,i) using only Gauss-Elimination operations. /// It is used in the inverse-function /// The result is stored in the global matrix A.</para> /// </summary> /// /// <exception cref="ArgumentException">Thrown if a multiplicative inverse of 0 is needed</exception> private void ComputeZerosAbove() { short tmp = 0; for (int k = _A.Length - 1; k > 0; k--) // the fixed row { for (int i = k - 1; i >= 0; i--) // rows { short factor1 = _A[i][k]; short factor2 = GF2Field.InvElem(_A[k][k]); if (factor2 == 0) { throw new CryptoAsymmetricSignException("ComputeInField:ComputeZerosAbove", "Matrix not invertible!", new ArgumentException()); } for (int j = k; j < 2 * _A.Length; j++) // columns { tmp = GF2Field.MultElem(_A[k][j], factor2); tmp = GF2Field.MultElem(factor1, tmp); _A[i][j] = GF2Field.AddElem(_A[i][j], tmp); } } } }
/// <summary> /// Elimination under the diagonal. /// <para>This function changes a matrix so that it contains only zeros under the diagonal(Ai,i) using only Gauss-Elimination operations. /// It is used in solveEquaton as well as in the function for finding an inverse of a matrix: inverse. /// Both of them use the Gauss-Elimination Method. /// The result is stored in the global matrix A</para> /// </summary> /// /// <param name="ForInverse">Shows if the function is used by the solveEquation-function or by the inverse-function and according to this creates matrices of different sizes.</param> /// /// <exception cref="ArgumentException">Thrown if the multiplicative inverse of 0 is needed</exception> private void ComputeZerosUnder(bool ForInverse) { // the number of columns in the global A where the tmp results are stored int length; short tmp = 0; // the function is used in inverse() - A should have 2 times more columns than rows if (ForInverse) { length = 2 * _A.Length; } // the function is used in solveEquation - A has 1 column more than rows else { length = _A.Length + 1; } // elimination operations to modify A so that that it contains only 0s under the diagonal for (int k = 0; k < _A.Length - 1; k++) // the fixed row { for (int i = k + 1; i < _A.Length; i++) { short factor1 = _A[i][k]; short factor2 = GF2Field.InvElem(_A[k][k]); // The element which multiplicative inverse is needed, is 0 in this case is the input matrix not invertible if (factor2 == 0) { throw new CryptoAsymmetricSignException("ComputeInField:ComputeZerosUnder", "Matrix not invertible!", new ArgumentException()); } for (int j = k; j < length; j++) {// columns // tmp=A[k,j] / A[k,k] tmp = GF2Field.MultElem(_A[k][j], factor2); // tmp = A[i,k] * A[k,j] / A[k,k] tmp = GF2Field.MultElem(factor1, tmp); // A[i,j]=A[i,j]-A[i,k]/A[k,k]*A[k,j]; _A[i][j] = GF2Field.AddElem(_A[i][j], tmp); } } } }
/// <summary> /// This function computes the inverse of a given matrix using the Gauss-Elimination method. /// <para>An exception is thrown if the matrix has no inverse</para> /// </summary> /// /// <param name="Coef">The matrix which inverse matrix is needed</param> /// /// <returns>The inverse matrix of the input matrix</returns> /// /// <exception cref="ArgumentException">Thrown if the given matrix is not invertible</exception> public short[][] Inverse(short[][] Coef) { try { short factor; short[][] inverse; _A = ArrayUtils.CreateJagged <short[][]>(Coef.Length, 2 * Coef.Length); if (Coef.Length != Coef[0].Length) { throw new CryptoAsymmetricSignException("ComputeInField:Inverse", "The matrix is not invertible!", new ArgumentException()); } // prepare: Copy coef and the identity matrix into the global A for (int i = 0; i < Coef.Length; i++) { // copy the input matrix coef into A for (int j = 0; j < Coef.Length; j++) { _A[i][j] = Coef[i][j]; } // copy the identity matrix into A. for (int j = Coef.Length; j < 2 * Coef.Length; j++) { _A[i][j] = 0; } _A[i][i + _A.Length] = 1; } // Elimination operations to get the identity matrix from the left side of A, modify A to get 0s under the diagonal ComputeZerosUnder(true); // modify A to get only 1s on the diagonal: A[i][j] =A[i][j]/A[i][i] for (int i = 0; i < _A.Length; i++) { factor = GF2Field.InvElem(_A[i][i]); for (int j = i; j < 2 * _A.Length; j++) { _A[i][j] = GF2Field.MultElem(_A[i][j], factor); } } //modify A to get only 0s above the diagonal. ComputeZerosAbove(); // copy the result (the second half of A) in the matrix inverse inverse = ArrayUtils.CreateJagged <short[][]>(_A.Length, _A.Length); for (int i = 0; i < _A.Length; i++) { for (int j = _A.Length; j < 2 * _A.Length; j++) { inverse[i][j - _A.Length] = _A[i][j]; } } return(inverse); } catch { // The matrix is not invertible! A new one should be generated! return(null); } }