static void mul_aux(vec_GF2& x, const vec_GF2& a, const mat_GF2& B) { long n = B.NumRows(); long l = B.NumCols(); if (n != a.length()) Error("matrix mul: dimension mismatch"); x.SetLength(l); clear(x); const _ntl_ulong *ap = a.rep.elts(); _ntl_ulong a_mask = 1; _ntl_ulong *xp = x.rep.elts(); long lw = (l + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; long i; for (i = 0; i < n; i++) { if (*ap & a_mask) { const _ntl_ulong *bp = B[i].rep.elts(); long j; for (j = 0; j < lw; j++) xp[j] ^= bp[j]; } a_mask <<= 1; if (!a_mask) { a_mask = 1; ap++; } } }
void power(mat_GF2& X, const mat_GF2& A, const ZZ& e) { if (A.NumRows() != A.NumCols()) Error("power: non-square matrix"); if (e == 0) { ident(X, A.NumRows()); return; } mat_GF2 T1, T2; long i, k; k = NumBits(e); T1 = A; for (i = k-2; i >= 0; i--) { sqr(T2, T1); if (bit(e, i)) mul(T1, T2, A); else T1 = T2; } if (e < 0) inv(X, T1); else X = T1; }
void AddToCol(mat_GF2& x, long j, const vec_GF2& a) // add a to column j of x // ALIAS RESTRICTION: a should not alias any row of x { long n = x.NumRows(); long m = x.NumCols(); if (a.length() != n || j < 0 || j >= m) Error("AddToCol: bad args"); long wj = j/NTL_BITS_PER_LONG; long bj = j - wj*NTL_BITS_PER_LONG; _ntl_ulong j_mask = 1UL << bj; const _ntl_ulong *ap = a.rep.elts(); _ntl_ulong a_mask = 1; long i; for (i = 0; i < n; i++) { if (*ap & a_mask) x[i].rep.elts()[wj] ^= j_mask; a_mask <<= 1; if (!a_mask) { a_mask = 1; ap++; } } }
void ident(mat_GF2& X, long n) { X.SetDims(n, n); clear(X); long i; for (i = 0; i < n; i++) X.put(i, i, to_GF2(1)); }
NTL_START_IMPL mat_GF2::mat_GF2(const mat_GF2& a) { _mat_GF2__numcols = 0; SetDims(a.NumRows(), a.NumCols()); _mat_GF2__rep = a._mat_GF2__rep; }
/** * Initializes matrix from specified array. * Data must be at least dimension of given matrix. */ int initMatrix(mat_GF2& M, long *data){ long i,j,n,m; for(i=0, n=M.NumRows(); i<n; i++){ for(j=0, m=M.NumCols(); j<m; j++){ M.put(i,j,data[n*i+j]); } } return 0; }
long IsDiag(const mat_GF2& A, long n, GF2 d) { if (A.NumRows() != n || A.NumCols() != n) return 0; if (d == 1) return IsIdent(A, n); else return IsZero(A); }
void transpose_aux(mat_GF2& X, const mat_GF2& A) { long n = A.NumRows(); long m = A.NumCols(); X.SetDims(m, n); clear(X); long i; for (i = 0; i < n; i++) AddToCol(X, i, A[i]); }
long gauss(mat_GF2& M, long w) { long k, l; long i, j; long pos; long n = M.NumRows(); long m = M.NumCols(); if (w < 0 || w > m) Error("gauss: bad args"); long wm = (m + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; l = 0; for (k = 0; k < w && l < n; k++) { long wk = k/NTL_BITS_PER_LONG; long bk = k - wk*NTL_BITS_PER_LONG; _ntl_ulong k_mask = 1UL << bk; pos = -1; for (i = l; i < n; i++) { if (M[i].rep.elts()[wk] & k_mask) { pos = i; break; } } if (pos != -1) { if (l != pos) swap(M[pos], M[l]); _ntl_ulong *y = M[l].rep.elts(); for (i = l+1; i < n; i++) { // M[i] = M[i] + M[l]*M[i,k] if (M[i].rep.elts()[wk] & k_mask) { _ntl_ulong *x = M[i].rep.elts(); for (j = wk; j < wm; j++) x[j] ^= y[j]; } } l++; } } return l; }
void cvt(mat_GF2& x, const mat_zz_p& a) { long n = a.NumRows(); long m = a.NumCols(); x.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) x.put(i, j, rep(a[i][j])); }
vec_GF2 GF2MatrixUtils::solve(mat_GF2 A, vec_GF2 b) { uint32_t nextRow = 0; for (uint32_t j =0; j < A.NumCols(); j++) { uint32_t i; for (i=nextRow; i < A.NumRows(); i++) { if (A[i][j] == 1) { break; } } if (i==A.NumRows()) { continue; } if (A[i][j] == 1) { if (nextRow !=i) { swap(A[nextRow],A[i]); swap(b[nextRow],b[i]); } for (uint32_t k=nextRow+1; k < A.NumRows(); k++) { if (A[k][j] == 1) { A[k] = A[k] + A[nextRow]; b[k] = b[k] + b[nextRow]; } } nextRow++; } } vec_GF2 sol; sol.SetLength(A.NumCols(), GF2(0)); int32_t lastRow=A.NumRows()-1; while (A[lastRow][A.NumCols()-1]==0) { if ((A[lastRow]*sol) != b[lastRow]) { throw(system_error()); } lastRow--; if (lastRow == -1) { throw(system_error()); } } for (int32_t j=A.NumCols()-1; j >= 0; j--) { if (lastRow == -1) { throw(system_error()); } if (A[lastRow][j]==0) { continue; } if ((A[lastRow]*sol) != b[lastRow]) { sol[j]=1; } lastRow--; } return sol; }
long IsIdent(const mat_GF2& A, long n) { if (A.NumRows() != n || A.NumCols() != n) return 0; if (n == 0) return 1; long i; for (i = 0; i < n; i++) if (!IsUnitVector(A[i], i)) return 0; return 1; }
void clear(mat_GF2& x) { long n = x.NumRows(); long i; for (i = 0; i < n; i++) clear(x[i]); }
void kernel(mat_GF2& X, const mat_GF2& A) { long m = A.NumRows(); long n = A.NumCols(); mat_GF2 M; long r; transpose(M, A); r = gauss(M); X.SetDims(m-r, m); clear(X); long i, j, k; vec_long D; D.SetLength(m); for (j = 0; j < m; j++) D[j] = -1; j = -1; for (i = 0; i < r; i++) { do { j++; } while (M.get(i, j) == 0); D[j] = i; } for (k = 0; k < m-r; k++) { vec_GF2& v = X[k]; long pos = 0; for (j = m-1; j >= 0; j--) { if (D[j] == -1) { if (pos == k) { v[j] = 1; // v.put(j, to_GF2(1)); } pos++; } else { v[j] = v*M[D[j]]; // v.put(j, v*M[D[j]]); } } } }
static void mul_aux(vec_GF2& x, const mat_GF2& A, const vec_GF2& b) { long n = A.NumRows(); long l = A.NumCols(); if (l != b.length()) Error("matrix mul: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) { x.put(i, A[i] * b); } }
void mul_aux(mat_GF2& X, const mat_GF2& A, const mat_GF2& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); if (l != B.NumRows()) Error("matrix mul: dimension mismatch"); X.SetDims(n, m); long i; for (i = 1; i <= n; i++) { mul_aux(X(i), A(i), B); } }
long operator==(const mat_GF2& a, const mat_GF2& b) { if (a.NumCols() != b.NumCols()) return 0; if (a.NumRows() != b.NumRows()) return 0; long n = a.NumRows(); long i; for (i = 0; i < n; i++) if (a[i] != b[i]) return 0; return 1; }
void diag(mat_GF2& X, long n, GF2 d) { if (d == 1) ident(X, n); else { X.SetDims(n, n); clear(X); } }
void mul(vec_GF2& x, const mat_GF2& A, const vec_GF2& b) { if (&b == &x || A.position1(x) != -1) { vec_GF2 tmp; mul_aux(tmp, A, b); x = tmp; } else mul_aux(x, A, b); }
void mul(vec_GF2& x, const vec_GF2& a, const mat_GF2& B) { if (&a == &x || B.position1(x) != -1) { vec_GF2 tmp; mul_aux(tmp, a, B); x = tmp; } else mul_aux(x, a, B); }
long IsZero(const mat_GF2& a) { long n = a.NumRows(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; }
void conv(mat_GF2& x, const vec_vec_GF2& a) { long n = a.length(); if (n == 0) { x.SetDims(0, 0); return; } long m = a[0].length(); long i; for (i = 1; i < n; i++) if (a[i].length() != m) Error("nonrectangular matrix"); x.SetDims(n, m); for (i = 0; i < n; i++) x[i] = a[i]; }
void add(mat_GF2& X, const mat_GF2& A, const mat_GF2& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) Error("matrix add: dimension mismatch"); X.SetDims(n, m); long mw = (m + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; long i; for (i = 0; i < n; i++) { _ntl_ulong *xp = X[i].rep.elts(); const _ntl_ulong *ap = A[i].rep.elts(); const _ntl_ulong *bp = B[i].rep.elts(); long j; for (j = 0; j < mw; j++) xp[j] = ap[j] ^ bp[j]; } }
long gauss(mat_GF2& M) { return gauss(M, M.NumCols()); }
void determinant(GF2& d, const mat_GF2& M_in) { long k, n; long i, j; long pos; n = M_in.NumRows(); if (M_in.NumCols() != n) Error("determinant: nonsquare matrix"); if (n == 0) { set(d); return; } mat_GF2 M; M = M_in; long wn = (n + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; for (k = 0; k < n; k++) { long wk = k/NTL_BITS_PER_LONG; long bk = k - wk*NTL_BITS_PER_LONG; _ntl_ulong k_mask = 1UL << bk; pos = -1; for (i = k; i < n; i++) { if (M[i].rep.elts()[wk] & k_mask) { pos = i; break; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); } _ntl_ulong *y = M[k].rep.elts(); for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] if (M[i].rep.elts()[wk] & k_mask) { _ntl_ulong *x = M[i].rep.elts(); for (j = wk; j < wn; j++) x[j] ^= y[j]; } } } else { clear(d); return; } } set(d); return; }
void inv(GF2& d, mat_GF2& X, const mat_GF2& A) { long n = A.NumRows(); if (A.NumCols() != n) Error("solve: nonsquare matrix"); if (n == 0) { X.SetDims(0, 0); set(d); } long i, j, k, pos; mat_GF2 M; M.SetDims(n, 2*n); vec_GF2 aa; aa.SetLength(2*n); for (i = 0; i < n; i++) { aa = A[i]; aa.SetLength(2*n); aa.put(n+i, 1); M[i] = aa; } long wn = ((2*n) + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; for (k = 0; k < n; k++) { long wk = k/NTL_BITS_PER_LONG; long bk = k - wk*NTL_BITS_PER_LONG; _ntl_ulong k_mask = 1UL << bk; pos = -1; for (i = k; i < n; i++) { if (M[i].rep.elts()[wk] & k_mask) { pos = i; break; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); } _ntl_ulong *y = M[k].rep.elts(); for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] if (M[i].rep.elts()[wk] & k_mask) { _ntl_ulong *x = M[i].rep.elts(); for (j = wk; j < wn; j++) x[j] ^= y[j]; } } } else { clear(d); return; } } vec_GF2 XX; XX.SetLength(2*n); X.SetDims(n, n); clear(X); for (j = 0; j < n; j++) { XX.SetLength(n+j+1); clear(XX); XX.put(n+j, to_GF2(1)); for (i = n-1; i >= 0; i--) { XX.put(i, XX*M[i]); } XX.SetLength(n); AddToCol(X, j, XX); } set(d); return; }
void solve(GF2& d, vec_GF2& X, const mat_GF2& A, const vec_GF2& b) { long n = A.NumRows(); if (A.NumCols() != n) Error("solve: nonsquare matrix"); if (b.length() != n) Error("solve: dimension mismatch"); if (n == 0) { X.SetLength(0); set(d); return; } long i, j, k, pos; mat_GF2 M; M.SetDims(n, n+1); for (i = 0; i < n; i++) { AddToCol(M, i, A[i]); } AddToCol(M, n, b); long wn = ((n+1) + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; for (k = 0; k < n; k++) { long wk = k/NTL_BITS_PER_LONG; long bk = k - wk*NTL_BITS_PER_LONG; _ntl_ulong k_mask = 1UL << bk; pos = -1; for (i = k; i < n; i++) { if (M[i].rep.elts()[wk] & k_mask) { pos = i; break; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); } _ntl_ulong *y = M[k].rep.elts(); for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] if (M[i].rep.elts()[wk] & k_mask) { _ntl_ulong *x = M[i].rep.elts(); for (j = wk; j < wn; j++) x[j] ^= y[j]; } } } else { clear(d); return; } } vec_GF2 XX; XX.SetLength(n+1); XX.put(n, 1); for (i = n-1; i >= 0; i--) { XX.put(i, XX*M[i]); } XX.SetLength(n); X = XX; set(d); return; }
int LinearAffineEq::checkInvertibleLinear(const bset & Ua, const bset & Ub, smap & mapA, smap & mapB, bsetElem * S1, bsetElem * S1inv, bsetElem * S2, bsetElem * S2inv, mat_GF2 & Ta, mat_GF2 & Tb, mat_GF2 & Tbinv, smap & mapBinv, bool AisA){ // Extract linearly independent vectors, to determine mapping. // We need matrix consisting of Avect to be invertible in order to determine // matrix representation of transformation. bset Avect = extractLinearlyIndependent(mapA); if (verbosity) { cout << "Size of linearly independent vectors: " << Avect.size() << endl; LinearAffineEq::dumpSet(Avect); } // Derive matrix representation of transformation, if possible // // Ta * Ainp = Aout => Ta = Aout * Ainp^{-1} mat_GF2 Ainp = LinearAffineEq::vectorSet2GF2matrix(Avect, 8), AinpInv; mat_GF2 Aout = LinearAffineEq::values2GF2matrix(Avect, mapA, 8); mat_GF2 TAinv; GF2 det; // Dimension check, each matrix has to have exactly 8 rows (dimension) and at least 8 columns // (number of equations, sample points) if ( Ainp.NumCols() < dim || Ainp.NumRows() != dim || Aout.NumCols() < dim || Aout.NumRows() != dim){ if (verbosity) cout << "Dimension mismatch for Ainp || Aout matrices " << endl; return -1; } if (verbosity){ cout << "Input matrix: " << endl; dumpMatrix(Ainp); cout << "Output matrix: " << endl; dumpMatrix(Aout); } // invertible? inv(det, AinpInv, Ainp); if (det == 0) { if (verbosity) cout << "A Matrix is not invertible! " << endl; return -2; } if (verbosity){ cout << "Inverse matrix: " << endl; dumpMatrix(AinpInv); } // obtain linear transformation Ta = Aout * AinpInv; if (verbosity) { cout << "Ta matrix: " << endl; dumpMatrix(Ta); } // invertible? inv(det, TAinv, Ta); if (det==0){ if (verbosity) cout << "Transformation is not linear & invertible!" << endl; return -3; } if (verbosity){ cout << "Transformation matrix repr. obtained!!!" << endl; dumpMatrix(Ta); } // // A is known (matrix representation), build lookup table // if (buildLookupTableAndCheck(Ta, 0, mapA)<0){ return -4; } // // Deriving mapping B from mapping A that is complete now and in matrix form. // // B * S2 = S1 * A // B(x) = S1 * A * S2^{-1} (x) // From this we derive mapping for B for basis vectors directly. // // Or B and A are swapped here and we want to compute values for A(x) // knowing mapping for B(x) (AisA==false) // // A(x) = S1inv * B * S2 (x) // Tb.SetDims(dim,dim); for(unsigned int i=0; i<dim; i++){ bsetElem base = 1 << i; bsetElem res = AisA ? S1[mapA[S2inv[base]]] : S1inv[mapA[S2[base]]]; for(unsigned int j=0; j<dim; j++){ Tb.put(j, i, (res & (1<<j)) > 0 ? 1 : 0); } } if (verbosity){ cout << "Mapping B derived" << endl; dumpMatrix(Tb); } // Transformation B invertibility test. // Inversion is needed for final test for relations properties with S-boxes. // If AisA==false, it does not mind, both relations has to be invertible. inv(det, Tbinv, Tb); if (det==0){ if (verbosity) cout << "B is not linear invertible transformation, cannot create inversion." << endl; return -4; } // build lookup table for B and check already precomputed values if (buildLookupTableAndCheck(Tb, 0, mapB)<0){ return -4; } // Whole range test for holding desired properties with Sboxes for which // they were designed. // For this we also need B^{-1} transformation. // // We apply this equation here: // B^{-1} * S1 * A = S2 // // If AisA==false, we have to reverse mapping here, Ta, Tb, Tainv, Tbinv are swapped, // but relations works only according to equations. We need to return mapBinv for // real B mapping (B^{-1} is needed to verify relations). if (AisA){ buildLookupTableAndCheck(Tbinv, 0, mapBinv); } else { mapBinv.clear(); buildLookupTableAndCheck(TAinv, 0, mapBinv); Tbinv = TAinv; } // // Again take swapping A and B into account. // if (verbosity) cout << "Testing matrix representation with |Ua| = " << Ua.size() << " and |Ub| = " << Ub.size() << endl; for(bsetElem iter = 0; iter < size; iter++){ bsetElem desiredResult = S2[iter]; bsetElem myResult = AisA ? mapBinv[S1[mapA[iter]]] : mapBinv[S1[mapB[iter]]]; if (desiredResult!=myResult){ if (verbosity){ cout << "Problem with relations, it does not work for: " << iter << endl; cout << "S2["<<iter<<"]= " << desiredResult << endl; cout << "B^{-1}[S1[A["<<iter<<"]]]=" << myResult << endl; } return -5; } } return 0; }