/* Author: Pate Williams (c) 1997 Exercise "5.6 The field GF(2 ^ 5) can be constructed as Z_2[x]/(x ^ 5 + x ^ 2 + 1). Perform the following computations in this field. (a) Compute (x ^ 4 + x ^ 2) * (x ^ 3 + x + 1). (b) Using the Extended Euclidean algorithm compute (x ^ 3 + x ^ 2) ^ - 1. (c) Using the square and multiply algorithm, compute x ^ 25." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 201. */ #include #include #define SIZE 32l void poly_mul(long m, long n, long *a, long *b, long *c, long *p) { long ai, bj, i, j, k, sum; *p = m + n; for (k = 0; k <= *p; k++) { sum = 0; for (i = 0; i <= k; i++) { j = k - i; if (i > m) ai = 0; else ai = a[i]; if (j > n) bj = 0; else bj = b[j]; sum += ai * bj; } c[k] = sum; } } void poly_div(long m, long n, long *u, long *v, long *q, long *r, long *p, long *s) { long j, jk, k, nk, vn = v[n]; for (j = 0; j <= m; j++) r[j] = u[j]; if (m < n) { *p = 0, *s = m; q[0] = 0; } else { *p = m - n, *s = n - 1; for (k = *p; k >= 0; k--) { nk = n + k; q[k] = r[nk] * pow(vn, k); for (j = nk - 1; j >= 0; j--) { jk = j - k; if (jk >= 0) r[j] = vn * r[j] - r[nk] * v[j - k]; else r[j] = vn * r[j]; } } while (*p > 0 && q[*p] == 0) *p = *p - 1; while (*s > 0 && r[*s] == 0) *s = *s - 1; } } void poly_exp_mod(long degreeA, long degreem, long n, long modulus, long *A, long *m, long *s, long *ds) { int zero; long dp, dq, dx = degreeA, i; long p[SIZE], q[SIZE], x[SIZE]; *ds = 0, s[0] = 1; for (i = 0; i <= dx; i++) x[i] = A[i]; while (n > 0) { if ((n & 1) == 1) { /* s = (s * x) % m; */ poly_mul(*ds, dx, s, x, p, &dp); poly_div(dp, degreem, p, m, q, s, &dq, ds); for (i = 0; i <= *ds; i++) s[i] %= modulus; zero = s[*ds] == 0, i = *ds; while (i > 0 && zero) { if (zero) *ds = *ds - 1; zero = s[--i] == 0; } } n >>= 1; /* x = (x * x) % m; */ poly_mul(dx, dx, x, x, p, &dp); poly_div(dp, degreem, p, m, q, x, &dq, &dx); for (i = 0; i <= dx; i++) x[i] %= modulus; zero = x[dx] == 0, i = dx; while (i > 0 && zero) { if (zero) dx--; zero = x[--i] == 0; } } } void poly_copy(long db, long *a, long *b, long *da) /* a = b */ { long i; *da = db; for (i = 0; i <= db; i++) a[i] = b[i]; } int poly_Extended_Euclidean(long db, long dn, long *b, long *n, long *t, long *dt) { int nonzero; long db0, dn0, dq, dr, dt0 = 0, dtemp, du, i; long b0[SIZE], n0[SIZE], q[SIZE]; long r[SIZE], t0[SIZE], temp[SIZE], u[SIZE]; *dt = 0; poly_copy(dn, n0, n, &dn0); poly_copy(db, b0, b, &db0); t0[0] = 0; t[0] = 1; poly_div(dn0, db0, n0, b0, q, r, &dq, &dr); nonzero = r[0] != 0; for (i = 1; !nonzero && i <= dr; i++) nonzero = r[i] != 0; while (nonzero) { poly_mul(dq, *dt, q, t, u, &du); if (dt0 < du) for (i = dt0 + 1; i <= du; i++) t0[i] = 0; for (i = 0; i <= du; i++) temp[i] = t0[i] - u[i]; dtemp = du; poly_copy(*dt, t0, t, &dt0); poly_copy(dtemp, t, temp, dt); poly_copy(db0, n0, b0, &dn0); poly_copy(dr, b0, r, &db0); poly_div(dn0, db0, n0, b0, q, r, &dq, &dr); nonzero = r[0] != 0; for (i = 1; !nonzero && i <= dr; i++) nonzero = r[i] != 0; } if (db0 != 0 && b0[0] != 1) return 0; return 1; } void poly_mod(long da, long p, long *a, long *new_da) { int zero; long i; for (i = 0; i <= da; i++) { a[i] %= p; if (a[i] < 0) a[i] += p; } zero = a[da] == 0; for (i = da - 1; zero && i >= 0; i--) { da--; zero = a[i] == 0; } *new_da = da; } void poly_write(char *label, long da, long *a) { long i; printf("%s", label); for (i = da; i >= 0; i--) printf("%ld ", a[i]); printf("\n"); } int main(void) { long da = 4, db = 3, dc = 3, dd = 5; long de, dq, dr, ds, p = 2; long a[5] = {0, 0, 1, 0, 1}; long b[4] = {1, 1, 0, 1}; long c[4] = {0, 0, 1, 1}; long d[6] = {1, 0, 1, 0, 0, 1}; long e[SIZE], q[SIZE], r[SIZE], s[SIZE]; poly_write("A = ", da, a); poly_write("B = ", db, b); poly_write("C = ", dc, c); poly_write("D = ", dd, d); poly_mul(da, db, a, b, e, &de); poly_mod(de, p, e, &de); poly_div(de, dd, e, d, q, r, &dq, &dr); poly_mod(dq, p, q, &dq); poly_mod(dr, p, r, &dr); poly_write("A * B mod 2 = ", de, e); poly_write("A * B / D mod 2 = ", dq, q); poly_write("A * B mod D, 2 = ", dr, r); if (!poly_Extended_Euclidean(dc, dd, c, d, e, &de)) printf("*error*\in poly_Extended_Euclidean\n"); poly_mod(de, p, e, &de); poly_write("C ^ - 1 mod D = ", de, e); poly_mul(dc, de, c, e, s, &ds); poly_mod(ds, p, s, &ds); poly_div(ds, dd, s, d, q, r, &dq, &dr); poly_mod(dr, p, r, &dr); poly_write("C * C ^ - 1 mod D, 2 = ", dr, r); dq = 1; q[0] = 0; q[1] = 1; poly_exp_mod(dq, dd, 7, p, q, d, s, &ds); poly_mod(ds, p, s, &ds); poly_write("x ^ 7 mod D, 2 = ", ds, s); poly_exp_mod(dq, dd, 9, p, q, d, s, &ds); poly_mod(ds, p, s, &ds); poly_write("x ^ 9 mod D, 2 = ", ds, s); poly_exp_mod(dq, dd, 10, p, q, d, s, &ds); poly_mod(ds, p, s, &ds); poly_write("x ^ 10 mod D, 2 = ", ds, s); poly_exp_mod(dq, dd, 25, p, q, d, s, &ds); poly_mod(ds, p, s, &ds); poly_write("x ^ 25 mod D, 2 = ", ds, s); return 0; }