/* Author: Pate Williams (c) 1997 Index-calculus algorithm for computing discrete logarithms. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al 3.6.5 Section 3.68 Algorithm pages 109 - 111. Also see 3.69 Example pages 110 - 111. */ #include #include #include #include #include "lip.h" #define BOUND 1000000l #define CRT_SIZE 128l #define DEBUG struct node { long expon, prime; }; verylong **create_matrix(long m, long n) { long i; verylong **zmatrix = calloc(m, sizeof(verylong *)); assert(zmatrix != 0); for (i = 0; i < m; i++) { zmatrix[i] = calloc(n, sizeof(verylong)); assert(zmatrix[i] != 0); } return zmatrix; } void delete_matrix(long m, long n, verylong **zmatrix) { long i, j; for (i = 0; i < m; i++) { for (j = 0; j < n; j++) zfree(&zmatrix[i][j]); free(zmatrix[i]); } free(zmatrix); } void zbinary_ext_gcd(verylong zx, verylong zy, verylong *za, verylong *zb, verylong *zv) /* returns a * x + b * y = v, v = gcd(x, y) */ { verylong zA = 0, zB = 0, zC = 0, zD = 0; verylong zX = 0, zY = 0, zc = 0, zg = 0; verylong zu = 0; zone(&zg); zcopy(zx, &zX); zcopy(zy, &zY); while (!zodd(zX) && !zodd(zY)) { zrshift(zX, 1l, &zc); zcopy(zc, &zX); zrshift(zY, 1l, &zc); zcopy(zc, &zY); zlshift(zg, 1l, &zc); zcopy(zc, &zg); } zcopy(zX, &zu); zcopy(zY, zv); zone(&zA); zzero(&zB); zzero(&zC); zone(&zD); do { while (!zodd(zu)) { zrshift(zu, 1l, &zc); zcopy(zc, &zu); if (!zodd(zA) && !zodd(zB)) { zrshift(zA, 1l, &zc); zcopy(zc, &zA); zrshift(zB, 1l, &zc); zcopy(zc, &zB); } else { zadd(zA, zY, &zc); zrshift(zc, 1l, &zA); zsub(zB, zX, &zc); zrshift(zc, 1l, &zB); } } while (!zodd(*zv)) { zrshift(*zv, 1l, &zc); zcopy(zc, zv); if (!zodd(zC) && !zodd(zD)) { zrshift(zC, 1l, &zc); zcopy(zc, &zC); zrshift(zD, 1l, &zc); zcopy(zc, &zD); } else { zadd(zC, zY, &zc); zrshift(zc, 1l, &zC); zsub(zD, zX, &zc); zrshift(zc, 1l, &zD); } } if (zcompare(zu, *zv) >= 0) { zsub(zu, *zv, &zc); zcopy(zc, &zu); zsub(zA, zC, &zc); zcopy(zc, &zA); zsub(zB, zD, &zc); zcopy(zc, &zB); } else { zsub(*zv, zu, &zc); zcopy(zc, zv); zsub(zC, zA, &zc); zcopy(zc, &zC); zsub(zD, zB, &zc); zcopy(zc, &zD); } } while (zscompare(zu, 0l) != 0); zcopy(zC, za); zcopy(zD, zb); zmul(zg, *zv, &zc); zcopy(zc, zv); zfree(&zA); zfree(&zB); zfree(&zC); zfree(&zD); zfree(&zX); zfree(&zY); zfree(&zc); zfree(&zg); zfree(&zu); } void zext_euclid(verylong za, verylong zb, verylong *zx, verylong *zy, verylong *zd) { verylong zA = 0, zB = 0, zc = 0, zq = 0, zr = 0; verylong zx1 = 0, zx2 = 0, zy1 = 0, zy2 = 0; if (zscompare(zb, 0l) == 0) { zone(zd); zone(zx); zzero(zy); } else { zcopy(za, &zA); zcopy(zb, &zB); zone(&zx2); zzero(&zx1); zzero(&zy2); zone(&zy1); while (zscompare(zB, 0l) > 0) { zdiv(zA, zB, &zq, &zr); zmul(zq, zx1, &zc); zsub(zx2, zc, zx); zmul(zq, zy1, &zc); zsub(zy2, zc, zy); zcopy(zB, &zA); zcopy(zr, &zB); zcopy(zx1, &zx2); zcopy(*zx, &zx1); zcopy(zy1, &zy2); zcopy(*zy, &zy1); } zcopy(zA, zd); zcopy(zx2, zx); zcopy(zy2, zy); } zfree(&zA); zfree(&zB); zfree(&zc); zfree(&zq); zfree(&zr); zfree(&zx1); zfree(&zx2); zfree(&zy1); zfree(&zy2); } void zinvmod_1(verylong zx, verylong zy, verylong *zi) { verylong zb = 0, zv = 0; zext_euclid(zx, zy, zi, &zb, &zv); if (zscompare(*zi, 0l) < 0) { zadd(*zi, zy, &zb); zcopy(zb, zi); } if (zscompare(zv, 1l) != 0) zzero(zi); zfree(&zb); zfree(&zv); } void gaussian_elimination(long m, long n, verylong zp, verylong *zb, verylong *zx, verylong **zm) { int found; long i, j, k, l; verylong zck = 0, zd = 0, zs = 0, zsum = 0, zt = 0; for (j = 0; j < n; j++) { found = 0, i = j; while (!found && i < m) { found = zscompare(zm[i][j], 0l) != 0; if (found) { zinvmod_1(zm[i][j], zp, &zd); found = zscompare(zd, 0l) != 0; } if (!found) i++; } if (i > j) { /* exchange colums */ for (l = j; l < n; l++) { zcopy(zm[i][l], &zt); zcopy(zm[j][l], &zm[i][l]); zcopy(zt, &zm[j][l]); } zcopy(zb[i], &zt); zcopy(zb[j], &zb[i]); zcopy(zt, &zb[j]); } for (k = j + 1; k < m; k++) { zmulmod(zd, zm[k][j], zp, &zck); for (l = j + 1; l < n; l++) { zmulmod(zck, zm[j][l], zp, &zt); zsubmod(zm[k][l], zt, zp, &zsum); zcopy(zsum, &zm[k][l]); } zmulmod(zck, zb[j], zp, &zt); zsubmod(zb[k], zt, zp, &zsum); zcopy(zsum, &zb[k]); } } for (i = n - 1; i >= 0; i--) { zzero(&zsum); for (j = i + 1; j < n; j++) { zmulmod(zm[i][j], zx[j], zp, &zt); zaddmod(zt, zsum, zp, &zs); zcopy(zs, &zsum); } zinvmod(zm[i][i], zp, &zd); zsubmod(zb[i], zsum, zp, &zt); zmulmod(zd, zt, zp, &zx[i]); } zfree(&zck); zfree(&zd); zfree(&zs); zfree(&zsum); zfree(&zt); } void Garner(long t, verylong *zm, verylong *zv, verylong *zx) /* solution of the Chinese remaider theorem */ { long i, j; verylong za = 0, zb = 0, zu = 0, zC[CRT_SIZE]; for (i = 0; i < CRT_SIZE; i++) zC[i] = 0; for (i = 1; i < t; i++) { zone(&zC[i]); for (j = 0; j <= i - 1; j++) { zinvmod(zm[j], zm[i], &zu); zmulmod(zu, zC[i], zm[i], &za); zcopy(za, &zC[i]); } } zcopy(zv[0], &zu); zcopy(zu, zx); for (i = 1; i < t; i++) { zsub(zv[i], *zx, &za); zmulmod(za, zC[i], zm[i], &zu); zone(&za); for (j = 0; j <= i - 1; j++) { zmul(za, zm[j], &zb); zcopy(zb, &za); } zmul(za, zu, &zb); zadd(*zx, zb, &za); zcopy(za, zx); } zfree(&za); zfree(&zb); zfree(&zu); for (i = 0; i < CRT_SIZE; i++) zfree(&zC[i]); } void trial_divide(struct node *p, verylong zn, long *n) { long e, q; verylong za = 0, zb = 0; zcopy(zn, &za); *n = 0; zpstart2(); do { e = 0; q = zpnext(); while (zsmod(za, q) == 0) { e++; zsdiv(za, q, &zb); zcopy(zb, &za); } if (e != 0) { p[*n].expon = e; p[*n].prime = q; *n = *n + 1; } } while (!zprobprime(za, 5l) && q < BOUND); if (zscompare(za, 1l) != 0) { p[*n].expon = 1; p[*n].prime = ztoint(za); *n = *n + 1; } zfree(&za); zfree(&zb); } void solve(long m, long n, verylong zn, verylong *zb, verylong *zx, verylong **zm) { long i, j, k, q; struct node p[32]; verylong zq = 0; verylong *zB = calloc(m, sizeof(verylong)), *zp; verylong *zv = calloc(n, sizeof(verylong)); verylong **zM = create_matrix(m, n), **zX; assert(zB != 0 && zv != 0); trial_divide(p, zn, &q); zp = calloc(q, sizeof(verylong)); assert(zp != 0); zX = create_matrix(q, n); for (i = 0; i < q; i++) { for (j = 0; j < m; j++) { for (k = 0; k < n; k++) zcopy(zm[j][k], &zM[j][k]); zcopy(zb[j], &zB[j]); } zintoz(p[i].prime, &zq); zsexp(zq, p[i].expon, &zp[i]); gaussian_elimination(m, n, zp[i], zB, zX[i], zM); } for (i = 0; i < n; i++) { for (j = 0; j < q; j++) zcopy(zX[j][i], &zv[j]); Garner(q, zp, zv, &zx[i]); } delete_matrix(m, n, zM); delete_matrix(q, n, zX); free(zB); free(zp); free(zv); zfree(&zq); } int trial_division(long t, struct node *p, verylong zn) { int c; long e, i, q, s = 0; verylong za = 0, zt = 0; zpstart2(); zcopy(zn, &zt); for (i = 0; i < t; i++) p[i].expon = p[i].prime = 0; do { q = zpnext(); e = 0; while (zsmod(zt, q) == 0) { e++; zsdiv(zt, q, &za); zcopy(za, &zt); } if (e != 0) { p[s].expon = e; p[s].prime = q; } else { p[s].expon = 0; p[s].prime = 0; } s++; c = zscompare(zt, 1l) == 0; } while (!c && s < t); zfree(&za); zfree(&zt); return c; } void index_calculus(long t, verylong za, verylong zb, verylong zn, verylong zp, verylong *zl) { int found = 0; long c = 1, count = 0, i, k, m = t + c; struct node *p = calloc(t, sizeof(struct node)); verylong *zc = calloc(m, sizeof(verylong)); verylong *zx = calloc(t, sizeof(verylong)); verylong **zm = create_matrix(m, t); verylong zd = 0, zk = 0, zq = 0, zr = 0, zs = 0; assert(p != 0); assert(zc != 0); assert(zx != 0); zrstarts(time(NULL)); while (count < m) { zrandomb(zn, &zk); #ifdef DEBUG switch (count) { case 0 : k = 100; break; case 1 : k = 18; break; case 2 : k = 12; break; case 3 : k = 62; break; case 4 : k = 143; break; case 5 : k = 206; break; } zintoz(k, &zk); #endif zexpmod(za, zk, zp, &zq); if (trial_division(t, p, zq)) { zcopy(zk, &zc[count]); for (i = 0; i < t; i++) { if (p[i].prime == 0) zzero(&zm[count][i]); else zintoz(p[i].expon, &zm[count][i]); } count++; } } #ifdef DEBUG { long j; for (i = 0; i < m; i++) { for (j = 0; j < t; j++) { zwrite(zm[i][j]); printf(" "); } zwriteln(zc[i]); } } #endif solve(m, t, zn, zc, zx, zm); #ifdef DEBUG for (i = 0; i < t; i++) zwriteln(zx[i]); #endif while (!found) { zrandomb(zn, &zk); zexp(za, zk, &zr); zmulmod(zb, zr, zp, &zq); if (trial_division(t, p, zq)) { found = 1; zzero(&zs); for (i = 0; i < t; i++) { zsmulmod(zx[i], p[i].expon, zn, &zr); zaddmod(zs, zr, zn, &zd); zcopy(zd, &zs); } zsubmod(zs, zk, zn, zl); } } zfree(&zd); zfree(&zk); zfree(&zn); zfree(&zq); zfree(&zr); zfree(&zs); for (i = 0; i < m; i++) zfree(&zc[i]); for (i = 0; i < t; i++) zfree(&zx[i]); delete_matrix(m, t, zm); } int main(void) { long t = 5l; verylong za = 0, zb = 0, zl = 0, zn = 0, zp = 0; zintoz(6l, &za); zintoz(13l, &zb); zintoz(228l, &zn); zintoz(229l, &zp); index_calculus(t, za, zb, zn, zp, &zl); zwriteln(zl); zfree(&za); zfree(&zb); zfree(&zl); zfree(&zn); zfree(&zp); return 0; }