Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 148

Chapter 02

2.107 2.142 2.143 2.149 2.221

Mathematical Background

Algorithm Extended Euclidean Algorithm exteuc.c (1,378) Algorithm Computing multiplicative inverses in Zn inverse.c (1,094) Algorithm Repeated square-and-multiply algorithm for exponentiation in Zn repeat.c (1,268) Algorithm Jacobi symbol (and Legendre symbol) computation jacobi.c (987) Algorithm Extended Euclidean algorithm in Zp[x] polyee.c freelip (8,642) Algorithm Extended Euclidean Algorithm exteuc.c (1,378)

2.107
/*

Author: Pate Williams (c) 1997 2.107 Algorithm Extended Euclidean algorithm See "Handbook of Applied Cryptography" by Alfred J. Menezes et al page 67. */ #include <stdio.h> #define DEBUG void extended_euclid(long a, long b, long *x, long *y, long *d) /* calculates a * *x + b * *y = gcd(a, b) = *d */ { long q, r, x1, x2, y1, y2; if (b == 0) { *d = a, *x = 1, *y = 0; return; } x2 = 1, x1 = 0, y2 = 0, y1 = 1; #ifdef DEBUG printf("------------------------------"); printf("-------------------\n"); printf("q r x y a b "); printf("x2 x1 y2 y1\n"); printf("------------------------------"); printf("-------------------\n"); #endif while (b > 0) {

} *d = a, *x = x2, *y = y2; #ifdef DEBUG printf("------------------------------"); printf("-------------------\n"); #endif

q = a / b, r = a - q * b; *x = x2 - q * x1, *y = y2 - q * y1; a = b, b = r; x2 = x1, x1 = *x, y2 = y1, y1 = *y; #ifdef DEBUG printf("%4ld %4ld %4ld %4ld ", q, r, *x, *y); printf("%4ld %4ld %4ld %4ld ", a, b, x2, x1); printf("%4ld %4ld\n", y2, y1); #endif

int main(void) { long a = 4864, b = 3458, d, x, y; extended_euclid(a, b, &x, &y, &d); printf("x = %ld y = %ld d = %ld\n", x, y, d); return 0; }

2.142
/*

Algorithm Computing multiplicative inverses in Zn inverse.c (1,094)


Pate Williams (c) 1997

Author:

*/

2.142 Algorithm Computing multiplicative inverses in Zn See "Handbook of Applied Cryptography" by Alfred J. Menezes et al page 71.

#include <stdio.h> void extended_euclid(long a, long b, long *x, long *y, long *d) /* calculates a * *x + b * *y = gcd(a, b) = *d */ { long q, r, x1, x2, y1, y2; if (b == 0) { *d = a, *x = 1, *y = 0; return; } x2 = 1, x1 = 0, y2 = 0, y1 = 1; while (b > 0) { q = a / b, r = a - q * b; *x = x2 - q * x1, *y = y2 - q * y1; a = b, b = r; x2 = x1, x1 = *x, y2 = y1, y1 = *y;

} *d = a, *x = x2, *y = y2; } long inverse(long a, long n) /* computes the inverse of a modulo n */ { long d, x, y; extended_euclid(a, n, &x, &y, &d); if (d == 1) return x; return 0; } int main(void) { long a = 5, n = 7; printf("the inverse of %ld modulo %2ld is %ld\n", a, n, inverse(a, n)); a = 2, n = 12; printf("the inverse of %ld modulo %2ld is %ld\n", a, n, inverse(a, n)); return 0; }

2.143
/* Author:

Algorithm Repeated square-and-multiply algorithm for exponentiation in Zn repeat.c (1,268)


Pate Williams (c) 1997

*/

2.143 Algorithm Repeated sqaure-and-mutiply algorithm for exponentiation in Zn See "Handbook of Applied Cryptography" by Alfred J. Menezes et al page 71.

#include <stdio.h> #define BITS_PER_LONG 32l #define DEBUG long long_to_binary(long K, long *k) { int found = 0; long a = K, i, l = 0, length; while (!found && l < BITS_PER_LONG) { found = ((a & 0x80000000l) >> 31) == 1; if (!found) a <<= 1, l++; } length = BITS_PER_LONG - l; for (i = 0; i < length; i++) k[i] = K & 1, K >>= 1; return length;

} long powmod(long a, long K, long n) { long A = a, b = 1, i, k[32]; long t = long_to_binary(K, k); if (K == 0) return b; if (k[0] == 1) b = a; #ifdef DEBUG printf("-------------\n"); printf("i k A B \n"); printf("-------------\n"); printf("%ld %ld %4ld %4ld\n", i = 0, k[i], A, b); #endif for (i = 1; i < t; i++) { A = (A * A) % n; if (k[i]) b = (A * b) % n; #ifdef DEBUG printf("%ld %ld %4ld %4ld\n", i, k[i], A, b); #endif } #ifdef DEBUG printf("-------------\n"); #endif return b; } int main(void) { long a = 5, K = 596, n = 1234; powmod(a, K, n); return 0; }

2.149
/* Author:

Algorithm Jacobi symbol (and Legendre symbol) computation jacobi.c (987)


Pate Williams (c) 1997

*/

2.149 Algorithm Jacobi symbol (and Legendre symbol) computation See "Hanbook of Applied Cryptography" by Alfred J. Menezes et al page 73.

#include <stdio.h> int JACOBI(long a, long n) { int s; long a1, b = a, e = 0, m, n1; if (a == 0) return 0;

if (a == 1) return 1; while ((b & 1) == 0) b >>= 1, e++; a1 = b; m = n % 8; if (!(e & 1)) s = 1; else if (m == 1 || m == 7) s = else if (m == 3 || m == 5) s = if (n % 4 == 3 && a1 % 4 == 3) if (a1 != 1) n1 = n % a1; else return s * JACOBI(n1, a1);

+ 1; - 1; s = - s; n1 = 1;

int main(void) { int j, k; long a = 158, n = 235; printf("a = %ld n = %ld (a / n) = %ld\n", a, n, JACOBI(a, n)); for (a = 1; a < 21; a++) { j = JACOBI(a, 3); k = JACOBI(a, 7); if (j != 0 && k != 0) printf("%2ld %2ld %2d %2d %2d\n", a, a * a % 21, j, k, JACOBI(a, 21)); } return 0; }

2.221
/* Author:

Algorithm Extended Euclidean algorithm in Zp[x] polyee.c freelip (8,642)


Pate Williams (c) 1997

*/

Polynomial extended Euclidean algorithm. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al 2.6.2 Section 2.2.1 Algorithm page 82.

#include <stdio.h> #include "lip.h" #define DEBUG #define POLY_SIZE 8192l void zpoly_mul(long m, long n, verylong *za, verylong *zb, verylong *zc, long *p) { long i, j, k; verylong zd = 0, zai = 0, zbk = 0, zsum = 0, zterm = 0; *p = m + n; for (k = 0; k <= *p; k++) {

zzero(&zsum); for (i = 0; i <= k; i++) { j = k - i; if (i > m) zzero(&zai); else zcopy(za[i], &zai); if (j > n) zzero(&zbk); else zcopy(zb[j], &zbk); zmul(zai, zbk, &zterm); zcopy(zsum, &zd); zadd(zterm, zd, &zsum); } zcopy(zsum, &zc[k]); } zfree(&zd); zfree(&zai); zfree(&zbk); zfree(&zsum); zfree(&zterm); } void zpoly_div(long m, long n, verylong *zu, verylong *zv, verylong *zq, verylong *zr, long *p, long *s) { long j, jk, k, nk; verylong za = 0, zb = 0, zvn = 0; zcopy(zv[n], &zvn); for (j = 0; j <= m; j++) zcopy(zu[j], &zr[j]); if (m < n) { *p = 0, *s = m; zzero(&zq[0]); } else { *p = m - n, *s = n - 1; for (k = *p; k >= 0; k--) { nk = n + k; zsexp(zvn, k, &za); zmul(zr[nk], za, &zq[k]); for (j = nk - 1; j >= 0; j--) { jk = j - k; if (jk >= 0) { zmul(zvn, zr[j], &za); zmul(zr[nk], zv[jk], &zb); zsub(za, zb, &zr[j]); } else { zcopy(zr[j], &za); zmul(zvn, za, &zr[j]); } } } while (*p > 0 && zscompare(zq[*p], 0l) == 0) *p = *p - 1; while (*s > 0 && zscompare(zr[*s], 0l) == 0) *s = *s - 1; } zfree(&za); zfree(&zb);

zfree(&zvn);

void zpoly_pow(long degreeA, long degreem, verylong zn, verylong *zA, verylong *zm, verylong *zs, long *ds) { long dp, dq, dx = degreeA, i; verylong za = 0, zb = 0, zp[POLY_SIZE], zq[POLY_SIZE], zx[POLY_SIZE], zy[POLY_SIZE]; for (i = 0; i < POLY_SIZE; i++) zp[i] = zq[i] = zx[i] = zy[i] = 0; *ds = 0; zcopy(zn, &za); zone(&zs[0]); for (i = 0; i <= dx; i++) zcopy(zA[i], &zx[i]); while (zscompare(za, 0l) > 0) { if (zodd(za)) { /* s = (s * x) % m; */ zpoly_mul(*ds, dx, zs, zx, zp, &dp); zpoly_div(dp, degreem, zp, zm, zq, zs, &dq, ds); } zcopy(za, &zb); zrshift(zb, 1l, &za); if (zscompare(za, 0l) > 0) { /* x = (x * x) % m; */ for (i = 0; i <= dx; i++) zcopy(zx[i], &zy[i]); zpoly_mul(dx, dx, zx, zy, zp, &dp); zpoly_div(dp, degreem, zp, zm, zq, zx, &dq, &dx); } } zfree(&za); zfree(&zb); for (i = 0; i < POLY_SIZE; i++) { zfree(&zp[i]); zfree(&zq[i]); zfree(&zx[i]); zfree(&zy[i]); } } void zpoly_sub(long da, long db, verylong *za, verylong *zb, verylong *zc, long *dc) { long i; verylong zz = 0; zzero(&zz); if (da >= db) { for (i = 0; i <= db; i++) zsub(za[i], zb[i], &zc[i]); for (i = db + 1; i <= da; i++) zcopy(za[i], &zc[i]); *dc = da; } else {

} zfree(&zz);

for (i = 0; i <= da; i++) zsub(za[i], zb[i], &zc[i]); for (i = da + 1; i <= db; i++) zsub(zz, zb[i], &zc[i]); *dc = db;

void zpoly_gcd(long degreeA, long degreeB, long p, verylong *zA, verylong *zB, verylong *za, long *da) { int nonzero = 0, zero; long db, dq, dr, i; verylong zc = 0, zp = 0; verylong zb[POLY_SIZE], zq[POLY_SIZE], zr[POLY_SIZE]; for (i = 0; i < POLY_SIZE; i++) zb[i] = zq[i] = zr[i] = 0; if (degreeA > degreeB) { *da = degreeA; db = degreeB; for (i = 0; i <= *da; i++) zcopy(zA[i], &za[i]); for (i = 0; i <= db; i++) zcopy(zB[i], &zb[i]); } else { *da = degreeB; db = degreeA; for (i = 0; i <= *da; i++) zcopy(zB[i], &za[i]); for (i = 0; i <= db; i++) zcopy(zA[i], &zb[i]); } for (i = 0; i <= db && !nonzero; i++) nonzero = zscompare(zb[i], 0l) != 0; while (nonzero) { zpoly_div(*da, db, za, zb, zq, zr, &dq, &dr); zintoz(p, &zp); for (i = 0; i <= dr; i++) { zcopy(zr[i], &zc); zmod(zc, zp, &zr[i]); } zero = 1; for (i = dr; i >= 0 && zero; i--) { zero = zscompare(zr[i], 0l) == 0; if (zero && dr > 0) dr--; } for (i = 0; i <= db; i++) zcopy(zb[i], &za[i]); *da = db; for (i = 0; i <= dr; i++) zcopy(zr[i], &zb[i]); db = dr; nonzero = 0; for (i = 0; i <= db && !nonzero; i++) nonzero = zscompare(zb[i], 0l) != 0; } zfree(&zc); zfree(&zp); for (i = 0; i < POLY_SIZE; i++) {

} }

zfree(&zb[i]); zfree(&zq[i]); zfree(&zr[i]);

void zpoly_copy(long da, verylong *za, verylong *zb, long *db) { long i; *db = da; for (i = 0; i <= da; i++) zcopy(za[i], &zb[i]); } void zpoly_print(long da, verylong *za) { long i; for (i = da; i >= 0; i--) { zwrite(za[i]); printf(" "); } printf("\n");

void zpoly_mod(long p, verylong *za, long *da) { long i; for (i = 0; i <= *da; i++) zintoz(zsmod(za[i], p), &za[i]); while (*da > 0 && zscompare(za[*da], 0l) == 0) *da = *da - 1; } void zpoly_ext_euclid(long dg, long dh, long p, verylong *zg, verylong *zh, verylong *zs, verylong *zt, verylong *zd, long *ds, long *dt, long *dd) { long da, dq, dr, ds1 = 0, ds2 = 0, dt1 = 0, dt2 = 0, i; verylong za[POLY_SIZE], zb[POLY_SIZE]; verylong zq[POLY_SIZE], zr[POLY_SIZE]; verylong zs1[POLY_SIZE], zs2[POLY_SIZE]; verylong zt1[POLY_SIZE], zt2[POLY_SIZE]; if (dh == 0 && zscompare(zh[0], 0l) == 0) { zpoly_copy(dg, zg, zd, dd); *ds = *dt = 0; zone(&zs[0]); zzero(&zt[0]); } for (i = 0; i < POLY_SIZE; i++) { za[i] = zb[i] = zq[i] = zr[i] = 0; zs1[i] = zs2[i] = zt1[i] = zt2[i] = 0; } zone(&zs2[0]); zzero(&zs1[0]);

zzero(&zt2[0]); zone(&zt1[0]); while (dh != 0 || zscompare(zh[0], 0l) != 0) { zpoly_div(dg, dh, zg, zh, zq, zr, &dq, &dr); zpoly_mod(p, zq, &dq); zpoly_mod(p, zr, &dr); zpoly_mul(dq, ds1, zq, zs1, za, &da); zpoly_sub(ds2, da, zs2, za, zs, ds); zpoly_mul(dq, dt1, zq, zt1, za, &da); zpoly_sub(dt2, da, zt2, za, zt, dt); zpoly_mod(p, zs, ds); zpoly_mod(p, zt, dt); zpoly_copy(dh, zh, zg, &dg); zpoly_copy(dr, zr, zh, &dh); zpoly_copy(ds1, zs1, zs2, &ds2); zpoly_copy(*ds, zs, zs1, &ds1); zpoly_copy(dt1, zt1, zt2, &dt2); zpoly_copy(*dt, zt, zt1, &dt1); #ifdef DEBUG printf("q = "); zpoly_print(dq, zq); printf("r = "); zpoly_print(dr, zr); printf("s = "); zpoly_print(*ds, zs); printf("t = "); zpoly_print(*dt, zt); printf("g = "); zpoly_print(dg, zg); printf("h = "); zpoly_print(dh, zh); printf("s2 = "); zpoly_print(ds2, zs2); printf("s1 = "); zpoly_print(ds1, zs1); printf("t2 = "); zpoly_print(dt2, zt2); printf("t1 = "); zpoly_print(dt1, zt1); #endif } zpoly_copy(dg, zg, zd, dd); zpoly_copy(ds2, zs2, zs, ds); zpoly_copy(dt2, zt2, zt, dt); for (i = 0; i < POLY_SIZE; i++) { zfree(&za[i]); zfree(&zb[i]); zfree(&zq[i]); zfree(&zr[i]); zfree(&zs1[i]); zfree(&zs2[i]); zfree(&zt1[i]); zfree(&zt2[i]); } } int main(void) { long dd, dg, dh, ds, dt, i, p = 2; verylong zg[POLY_SIZE], zh[POLY_SIZE]; verylong zd[POLY_SIZE], zs[POLY_SIZE]; verylong zt[POLY_SIZE]; for (i = 0; i < POLY_SIZE; i++) zd[i] = zg[i] = zh[i] = zs[i] = zt[i] = 0; dg = 10; for (i = 0; i <= dg; i++) zzero(&zg[i]);

zintoz(1l, &zg[10]); zintoz(1l, &zg[9]); zintoz(1l, &zg[8]); zintoz(1l, &zg[6]); zintoz(1l, &zg[5]); zintoz(1l, &zg[4]); zintoz(1l, &zg[0]); dh = 9; for (i = 0; i <= dh; i++) zzero(&zh[i]); zintoz(1l, &zh[9]); zintoz(1l, &zh[6]); zintoz(1l, &zh[5]); zintoz(1l, &zh[3]); zintoz(1l, &zh[2]); zintoz(1l, &zh[0]); zpoly_ext_euclid(dg, dh, p, zg, zh, zs, zt, zd, &ds, &dt, &dd); printf("s = "); zpoly_print(ds, zs); printf("t = "); zpoly_print(dt, zt); printf("d = "); zpoly_print(dd, zd); for (i = 0; i < POLY_SIZE; i++) { zfree(&zd[i]); zfree(&zg[i]); zfree(&zh[i]); zfree(&zs[i]); zfree(&zt[i]); } return 0;

Chapter 03

Number-Theoretic Reference Problems

3.14 3.21 3.34 3.44 3.56 3.60 3.68 3.105 3.111

Algorithm Pollard's p - 1 algorithm for factoring integers pminone freelip (5,665) Algorithm Quadratic sieve algorithm for factoring integers mpqs.c freelip (13,128) Algorithm Finding square roots modulo a prime p sqrtmod.c (3,090) Algorithm Finding square roots modulo n given its prime factors p and q fsroots.c freelip (3,749) Algorithm Baby-step giant-step for computing discrete logarithms dlp.c (5,234) Algorithm Pollard's rho algorithm for computing discrete logarithms dlp.c (5,234) Algorithm Index-calculus algorithm for discrete logarithms in cyclic groups index.c freelip (11,083) Algorithm Solving subset problems using LLL-algorithm knapsack.c (5,373) Algorithm Berlekamp's Q-matrix algorithm for factoring polynomials over finte fields polyfact.c freelip (12,831) Algorithm Pollard's p - 1 algorithm for factoring integers pminone freelip (5,665)
Pate Williams (c) 1997

3.14
/* Author:

Multiple precision p - 1 factoring method. See Algorithm 8.8.2 "A Course in Computational Algebraic Number Theory" by Henri Cohen page 439. The command line is as follows: pminone base exponent addend where base, exponent, and addend are long integers, factors base ^ exponent + addend. */ #include <stdio.h> #include <stdlib.h>

#include <time.h> #include "lip.h" #define B 1000000l #define NUMBER_PRIMES 78498l typedef struct Node * NodePtr; struct Node { long expon; verylong value; NodePtr next; }; int Insert(verylong v, NodePtr *list) { NodePtr currentPtr, newPtr, previousPtr; newPtr = malloc(sizeof(struct Node)); if (newPtr == 0) return 0; newPtr->expon = 1l; newPtr->value = 0; zcopy(v, &newPtr->value); previousPtr = 0; for (currentPtr = *list; currentPtr != 0 && zcompare(v, currentPtr->value) > 0; currentPtr = currentPtr->next) previousPtr = currentPtr; if (currentPtr != 0 && zcompare(v, currentPtr->value) == 0) { currentPtr->expon++; zfree(&newPtr->value); free(newPtr); } else if (previousPtr == 0) { newPtr->next = *list; *list = newPtr; } else { previousPtr->next = newPtr; newPtr->next = currentPtr; } return 1;

void Delete(NodePtr *list) { NodePtr currentPtr = *list, tempPtr; while (currentPtr != 0) { zfree(&currentPtr->value); tempPtr = currentPtr; currentPtr = currentPtr->next; free(tempPtr); } *list = 0; } void zpow(long base, long exponent, verylong *zs)

static verylong za = 0, zt = 0; zone(zs); zzero(&zt); zsadd(zt, base, &zt); while (exponent > 0) { zcopy(*zs, &za); if ((exponent & 1) == 1) zmul(za, zt, zs); exponent >>= 1; zcopy(zt, &za); zmul(za, za, &zt); }

int MillerRabin(int C, verylong zn) { int i, j, k = 0; static verylong za = 0, zb = 0, zar = 0, zn1 = 0, zr = 0; zsadd(zn, - 1l, &zn1); zcopy(zn1, &zr); if (zscompare(zn, 4l) < 1) return 1; if (zsmod(zn, 2l) == 0) return 0; while (zsmod(zr, 2l) == 0) { k++; zcopy(zr, &za); zsdiv(za, 2l, &zr); if (zsmod(zr, 2l) == 1l) break; } for (j = 0; j < C; j++) { zrandomb(zn1, &za); if (zscompare(za, 2l) < 0) { zzero(&zb); zsadd(zb, 2, &za); } zexpmod(za, zr, zn, &zar); if (zscompare(zar, 1l) != 0 && zcompare(zar, zn1) != 0) { i = 0; do { zcopy(zar, &za); zmul(za, za, &zar); zcopy(zar, &za); zmod(za, zn, &zar); if (zcompare(zar, zn1) == 0) break; i++; } while (i < k); if (i == k) return 0; } } return 1;

int FirstStage(long k, verylong *zN, long x0, long *p, verylong *zx, NodePtr *list) { long c = 0, i = - 1, j = i, l, q, q1;

static verylong zg = 0, zq1 = 0, zt = 0, zx1 = 0, zy = 0; zzero(&zg); zsadd(zg, x0, zx); zcopy(*zx, &zy); L2: i++; if (i >= k) { zsadd(*zx, - 1l, &zx1); zgcd(zx1, *zN, &zg); if (zscompare(zg, 1l) == 0) return 0; else { i = j; zcopy(zy, zx); goto L5; } } else { q = p[i]; q1 = q; l = B / q; } L3: while (q1 <= l) q1 *= q; zzero(&zt); zsadd(zt, q1, &zq1); zcopy(*zx, &zt); zexpmod(zt, zq1, *zN, zx); if (++c < 20) goto L2; L4: zsadd(*zx, - 1l, &zx1); zgcd(zx1, *zN, &zg); if (zscompare(zg, 1l) == 0) { c = 0; j = i; zcopy(*zx, &zy); goto L2; } else { i = j; zcopy(zy, zx); } L5: i++; q = p[i]; q1 = q; L6: zzero(&zt); zsadd(zt, q , &zq1); zcopy(*zx, &zt); zexpmod(zt, zq1, *zN, zx); zsadd(*zx, - 1l, &zx1); zgcd(zx1, *zN, &zg); if (zscompare(zg, 1l) == 0) { q1 *= q; if (q1 <= B) goto L6; else goto L5; }

else { if (zcompare(zg, *zN) < 0) { Insert(zg, list); zcopy(*zN, &zq1); zdiv(zq1, zg, zN, &zx1); return 1; } if (zcompare(zg, *zN) == 0) return 0; } return 1; } int main(int argc, char *argv[]) { double time; long addend, base, exponent, i, j, *p; NodePtr list = 0, node; clock_t time0 = clock(); verylong zn = 0, zx = 0; if (argc != 4) { printf("usage: pminone base exponent addend\n"); printf("where number to be factored is\n"); printf("base ^ exponent + addend\n"); exit(1); } base = atol(argv[1]), exponent = atol(argv[2]); addend = atol(argv[3]); zpow(base, exponent, &zn); zsadd(zn, addend, &zn); zwrite(zn); printf(" is "); if (MillerRabin(4, zn)) printf("prime\n"); else { printf("composite\nfactors:\n"); p = (long *) malloc(NUMBER_PRIMES * sizeof(long)); for (i = 0; i < NUMBER_PRIMES; i++) p[i] = zpnext(); i = 0; j = p[0]; do { while (!FirstStage(NUMBER_PRIMES, &zn, j, p, &zx, &list) && i < NUMBER_PRIMES) i++, j = p[i]; j = p[++i]; } while (!MillerRabin(4, zn) && i < NUMBER_PRIMES); Insert(zn, &list); for (node = list; node != 0; node = node->next) { printf("\t"); zwrite(node->value); if (node->expon != 1) printf(" ^ %ld\n", node->expon); else printf("\n"); } Delete(&list); free(p);

} zfree(&zn); zfree(&zx); time = (clock() - time0) / (double) CLK_TCK; printf("total time required: %lf seconds\n", time); return 0; }

3.21
/* Author:

Algorithm Quadratic sieve algorithm for factoring integers mpqs.c freelip (13,128)
Pate Williams (c) 1997

Quadratic sieve factoring algorithm. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al 3.21 Algorithm page 96. Also see "A Course in Computational Algebraic Number Theory" by Henri Cohen Section 10.4.2 pages 492 - 493. The command line is as follows: mpqs number_primes long_integer where long_integer is to be factored or mpqs number_primes base exponent addend where the number base ^ exponent + addend is to be factored. <stdio.h> <stdlib.h> <math.h> <time.h> "lip.h"

*/

#include #include #include #include #include

#define LARGE_PRIME_LIMIT 10000l #define NUMBER_PRIMES 1229l #define TRIAL_DIVIDE_LIMIT 100000l typedef struct Node * NodePtr; struct Node { long expon; verylong value; NodePtr next; }; int Insert(int e, verylong v, NodePtr *list) { NodePtr currentPtr, newPtr, previousPtr; newPtr = malloc(sizeof(struct Node)); if (newPtr == 0) return 0;

newPtr->expon = e; newPtr->value = 0; zcopy(v, &newPtr->value); previousPtr = 0; for (currentPtr = *list; currentPtr != 0 && zcompare(v, currentPtr->value) > 0; currentPtr = currentPtr->next) previousPtr = currentPtr; if (currentPtr != 0 && zcompare(v, currentPtr->value) == 0) { currentPtr->expon++; zfree(&newPtr->value); free(newPtr); } else if (previousPtr == 0) { newPtr->next = *list; *list = newPtr; } else { previousPtr->next = newPtr; newPtr->next = currentPtr; } return 1;

void Delete(NodePtr *list) { NodePtr currentPtr = *list, tempPtr; while (currentPtr != 0) { zfree(&currentPtr->value); tempPtr = currentPtr; currentPtr = currentPtr->next; free(tempPtr); } *list = 0; } long Find(long value, long *array) { long hi = NUMBER_PRIMES - 1, lo = 0, mid; for (;;) { mid = (hi + lo) / 2; if (value == array[mid]) return mid; if (value < array[mid]) hi = mid - 1; else lo = mid + 1; if (lo > hi) return - 1; }

void zpow(long base, long exponent, verylong *zs) { static verylong za = 0, zt = 0; zone(zs); zzero(&zt); zsadd(zt, base, &zt); while (exponent > 0) {

} }

zcopy(*zs, &za); if ((exponent & 1) == 1) zmul(za, zt, zs); exponent >>= 1; zcopy(zt, &za); zmul(za, za, &zt);

void zQx(long x, verylong zA, verylong zB, verylong zN, verylong *zQ) /* Q(x) = ((A * x + B) ^ 2 - N) / A */ { static verylong zu = 0, zv = 0; zintoz(x, &zv); zmul(zv, zA, &zu); zadd(zu, zB, &zv); zmul(zv, zv, &zu); zsub(zu, zN, &zv); zdiv(zv, zA, zQ, &zu);

int TrialDivision(char *e, long t, long *p, long *q, verylong *zq) /* returns 1 if number can be factored using the prime base and possibly one large prime */ { long count, i, r; static verylong zr = 0; for (i = 0; i < t; i++) e[i] = 0; if (zscompare(*zq, 0l) < 0) { e[0] = 1; znegate(zq); } for (i = 1; i < t; i++) { r = p[i]; if (zsmod(*zq, r) == 0l) { count = 0; do { count++; zsdiv(*zq, r, &zr); zcopy(zr, zq); } while (zsmod(*zq, r) == 0); e[i] = (char) count; if (zscompare(*zq, 1l) == 0) return 1; if (zprobprime(*zq, 5)) { if (zscompare(*zq, LARGE_PRIME_LIMIT) <= 0) { r = ztoint(*zq); e[Find(r, q)] = (char) 1; return 1; } return 0; } } } return 0;

int TrialDivide(verylong *zn, NodePtr *list) /* returns 1 if last factor is prime 0 otherwise */ { int flag1 = 0, flag2 = 0, found; long count, p; NodePtr l; static verylong zp = 0, zr = 0; zpstart2(); do { p = zpnext(); if (zsmod(*zn, p) == 0) { count = 0; do { count++; zsdiv(*zn, p, &zr); zcopy(zr, zn); } while (zsmod(*zn, p) == 0); zintoz(p, &zp); found = 0; for (l = *list; l != 0 && !found;) { found = zcompare(zp, l->value) == 0; if (!found) l = l->next; } if (found) l->expon++; else Insert(count, zp, list); flag1 = zscompare(*zn, 1l) == 0; flag2 = zprobprime(*zn, 5); } } while (p <= TRIAL_DIVIDE_LIMIT && !flag1 && !flag2); if (!flag1) Insert(1, *zn, list); return flag2;

int mpqs(long n, verylong *zn, NodePtr *list) /* returns - 1 if not enough memory 0 if number not completely factored 1 otherwise */ { char D, Msi, f[NUMBER_PRIMES], z[NUMBER_PRIMES], **e, **v; int flag1 = 0, flag2, found, ln2, lnq, *lnp, *sieve; long b, i = 0, j, k, l, length, m, s, t = 0, t1, x, x_max, x_min; long b_max, b_min, size, q[NUMBER_PRIMES], r, r1, r2, *c, *p, *x1, *x2; static verylong zA = 0, zB = 0, zD = 0; static verylong za = 0, zb = 0, zc = 0, zd = 0, zq = 0, zt = 0; static verylong zr = 0, zx = 0, zy = 0; verylong *a; ln2 = log(LARGE_PRIME_LIMIT); p = (long *) malloc(n * sizeof(long)); p[t++] = - 1l; /* get the prime base of the first n primes such that (N / p) = 1, where (* / *) is the Jacobi symbol */ zpstart2(); do { s = zpnext(); zintoz(s, &zq);

if (i < NUMBER_PRIMES) q[i++] = s; m = zjacobi(*zn, zq); if (m == 0 || m == 1) p[t++] = s; } while (t < n); while (i < NUMBER_PRIMES) q[i++] = zpnext(); t1 = t + 1; b_max = p[t + 1] + 1; b_min = - b_max; size = b_max - b_min + 1; /* allocate the required matrices and vectors */ sieve = (int *) malloc(size * sizeof(int)); a = (verylong *) malloc(t1 * sizeof(verylong)); e = (char **) malloc(t1 * sizeof(char *)); v = (char **) malloc(t1 * sizeof(char *)); c = (long *) malloc(t1 * sizeof(long)); lnp = (int *) malloc(t * sizeof(int)); x1 = (long *) malloc(t * sizeof(long)); x2 = (long *) malloc(t * sizeof(long)); for (i = 0; i < t1; i++) { a[i] = 0; e[i] = (char *) malloc(NUMBER_PRIMES * sizeof(char)); v[i] = (char *) malloc(NUMBER_PRIMES * sizeof(char)); } if (a == 0 || e == 0 || v == 0 || e[t1 - 1] == 0 || v[t1 - 1] == 0 || c == 0 || lnp == 0 || p == 0 || sieve == 0 || x1 == 0 || x2 == 0) { /* memory allocation error */ for (i = 0; i < t1; i++) { zfree(&a[i]); free(e[i]); free(v[i]); } free(a); free(e); free(v); free(c); free(p); free(x1); free(x2); free(lnp); free(sieve); return - 1; } for (i = 1; i < t; i++) lnp[i] = log(p[i]); /* calculate the minimum length of the coefficient A */ zsmul(*zn, 2l, &za); zsqrt(za, &zb, &zd); zsdiv(zb, b_max, &za); length = z2log(za); if (length < 3) length = 3; zpstart2(); for (i = 0; i < t1;) { do zrandomprime(length, 5, &zA, zrandomb); while (zjacobi(*zn, zA) != 1); /* calculate polynomial coefficients A, and B*/ if (zcompare(*zn, zA) >= 0)

zmod(*zn, zA, &zr); else zcopy(*zn, &zr); zsqrtmod(zr, zA, &zB); zcopy(zB, &zb); zmul(zb, zb, &za); zsub(za, *zn, &zb); zcopy(zB, &zD); znegate(&zD); zdiv(zB, zA, &za, &zb); zcopy(za, &zb); znegate(&zb); zsadd(zb, b_min, &zt); x_min = ztoint(zt); zsadd(za, b_max, &zt); x_max = ztoint(zt); /* calculate the roots of the polynomial modulo the prime base */ for (l = 1; l < t; l++) { r = p[l]; zintoz(r, &zt); if (zcompare(*zn, zt) >= 0) zmod(*zn, zt, &zr); else zcopy(*zn, &zr); zsqrtmod(zr, zt, &za); s = ztoint(za); zsadd(zD, s, &zt); zdiv(zt, zA, &za, &zb); x1[l] = zsmod(za, r); zsadd(zD, - s, &zt); zdiv(zD, zA, &za, &zb); x2[l] = zsmod(za, r); } for (x = x_min; x <= x_max && i < t1; x++) { zQx(x, zA, zB, *zn, &zq); zcopy(zq, &zt); zabs(&zt); lnq = zln(zt); /* initialize the sieve to ln(Q(x)) */ for (b = 0; b < size; b++) sieve[b] = lnq; for (l = 1; l < t; l++) { r = p[l]; lnq = lnp[l]; r1 = (x - x1[l]) % r; if (r1 < 0) r1 += r; for (m = r1; m < size; m += r) sieve[m] -= lnq; if (x1[l] == x2[l]) continue; r2 = (x - x2[l]) % r; if (r2 < 0) r2 += r; for (m = r2; m < size; m += r) sieve[m] -= lnq; } for (b = 0; b < size && i < t1; b++) { if (sieve[b] <= 4 * ln2) { if (TrialDivision(e[i], t, p, q, &zq)) {

} } } }

/* a[i] = A * x + B */ zsmul(zA, x, &za); zadd(za, zB, &a[i]); for (l = 0; l < NUMBER_PRIMES; l++) v[i][l] = (char) (e[i][l] % 2); i++; printf("\b\b\b\b\b\b\b%6ld", i);

} t = NUMBER_PRIMES; /* find the kernel of the v matrix over F2 */ if (i == t1) { for (k = 0; k < t1; k++) { found = 0, j = 0; while (!found && j < t1) { found = v[k][j] != 0 && c[j] < 0; if (!found) j++; } if (found) { v[k][j] = 1; for (i = 0; i < t; i++) { if (i != j) { D = v[k][i]; v[k][i] = 0; for (s = k + 1; s < t1; s++) { Msi = (char) (v[s][i] + D * v[s][j]); Msi &= (char) 1; v[s][i] = Msi; } } } c[j] = k; } else { for (j = 0; j < t; j++) z[j] = 0; for (j = 0; j < t; j++) { if (j == k) z[j] = 1; else for (s = 0; s < t; s++) if (c[s] == j) z[j] = v[k][s]; } zone(&za); for (i = 0; i < t1; i++) { if (z[i] == 1) { zcopy(za, &zt); zmul(zt, a[i], &za); } } zmod(za, *zn, &zx); for (j = 0; j < t; j++) { s = 0; for (i = 0; i < t1; i++) if (z[i] == 1) s += e[i][j]; f[j] = (char) (s / 2);

} }

} zone(&za); for (j = 1; j < t; j++) { zintoz(p[j], &zc); zintoz(f[j], &zb); zexp(zc, zb, &zt); zcopy(za, &zb); zmul(zt, zb, &za); } if (f[0] >= 1) znegate(&za); zmod(za, *zn, &zy); zmod(zy, *zn, &zt); if (zcompare(zx, zt) != 0) { zsub(zx, zy, &zt); zabs(&zt); zgcd(zt, *zn, &zd); if (zscompare(zd, 1l) != 0) { zdiv(*zn, zd, &zt, &za); zcopy(zt, zn); if (zprobprime(zd, 5)) { Insert(1, zd, list); break; } else flag1 |= TrialDivide(&zd, list); if (zscompare(*zn, 1l) == 0) break; } }

} flag2 = 0; if (zscompare(*zn, 1l) != 0) { if (zprobprime(*zn, 5)) Insert(1, *zn, list); else flag2 = TrialDivide(zn, list); } /* free up the memory that was allocated */ for (i = 0; i < t1; i++) { zfree(&a[i]); free(e[i]); free(v[i]); } free(a); free(e); free(v); free(c); free(p); free(x1); free(x2); free(lnp); free(sieve); return flag1 | flag2;

int main(int argc, char *argv[]) { double time; long addend, base, exponent, n;

NodePtr list = 0, node; clock_t time0 = clock(); verylong zn = 0; if (argc != 3 && argc != 5) { printf("usage: mpqs n number\n"); printf(" mpqs n base exponent addend\n"); printf("where number to be factored is either\n"); printf("number or base ^ exponent + addend\n"); printf("n is the number of primes in factor base\n"); exit(1); } n = atol(argv[1]); base = atol(argv[2]); if (argc == 3) { verylong zt = 0; zzero(&zt); zsadd(zt, base, &zn); zfree(&zt); } else { exponent = atol(argv[3]); addend = atol(argv[4]); zpow(base, exponent, &zn); zsadd(zn, addend, &zn); } zwrite(zn); printf(" is "); if (zprobprime(zn, 5)) printf("prime\n"); else { int flag; long same; verylong zt = 0; printf("composite\n"); zcopy(zn, &zt); flag = mpqs(n, &zn, &list); if (flag == - 1) printf("*error*\ninsufficient memory\n"); else { same = zcompare(zn, zt) == 0; zfree(&zt); if (same) printf("\n*error*\nnumber not factored\n"); else { printf("\nfactors:\n"); for (node = list; node != 0; node = node->next) { printf("\t"); zwrite(node->value); if (node->expon != 1) printf(" ^ %ld\n", node->expon); else printf("\n"); } if (!flag) printf("last factor is composite\n"); } }

Delete(&list); } zfree(&zn); time = (clock() - time0) / (double) CLK_TCK; printf("total time required: %f seconds\n", time); return 0; }

3.34
/*

Algorithm Finding square roots modulo a prime p sqrtmod.c (3,090)


Pate Williams (c) 1998

Author:

3.34 Algorithm Finding square roots modulo a prime. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al page 100. */ #include <stdio.h> #include <stdlib.h> int JACOBI(long a, long n) { int s; long a1, b = a, e = 0, m, n1; if (a == 0) return 0; if (a == 1) return 1; while ((b & 1) == 0) b >>= 1, e++; a1 = b; m = n % 8; if (!(e & 1)) s = 1; else if (m == 1 || m == 7) s = else if (m == 3 || m == 5) s = if (n % 4 == 3 && a1 % 4 == 3) if (a1 != 1) n1 = n % a1; else return s * JACOBI(n1, a1); } void extended_euclid(long a, long b, long *x, long *y, long *d) /* calculates a * *x + b * *y = gcd(a, b) = *d */ { long q, r, x1, x2, y1, y2; if (b == 0) { *d = a, *x = 1, *y = 0; return; } x2 = 1, x1 = 0, y2 = 0, y1 = 1; #ifdef DEBUG printf("------------------------------"); printf("-------------------\n"); printf("q r x y a b ");

+ 1; - 1; s = - s; n1 = 1;

printf("x2 x1 y2 y1\n"); printf("------------------------------"); printf("-------------------\n"); #endif while (b > 0) { q = a / b, r = a - q * b; *x = x2 - q * x1, *y = y2 - q * y1; a = b, b = r; x2 = x1, x1 = *x, y2 = y1, y1 = *y; #ifdef DEBUG printf("%4ld %4ld %4ld %4ld ", q, r, *x, *y); printf("%4ld %4ld %4ld %4ld ", a, b, x2, x1); printf("%4ld %4ld\n", y2, y1); #endif } *d = a, *x = x2, *y = y2; #ifdef DEBUG printf("------------------------------"); printf("-------------------\n"); #endif } long inverse(long a, long b) /* returns the inverse of a modulo b if it exists 0 otherwise */ { long d, x, y; extended_euclid(a, b, &x, &y, &d); if (d == 1) return x; return 0; } long exp_mod(long x, long b, long n) /* returns x ^ b mod n */ { long a = 1, s = x; while (b != 0) { if (b & 1) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } return a;

long square_root_mod(long a, long p) /* returns the square root of a modulo an odd prime p if it exists 0 otherwise */ { long ai, b, c, d, e, i, r, s = 0, t = p - 1; /* is a quadratic nonresidue */ if (JACOBI(a, p) == - 1) return 0; /* find quadratic nonresidue */ do do b = rand() % p; while (b == 0); while (JACOBI(b, p) != - 1);

/* write p - 1 = 2 ^ s * t for odd t */ while (!(t & 1)) s++, t >>= 1; ai = inverse(a, p); c = exp_mod(b, t, p); r = exp_mod(a, (t + 1) / 2, p); for (i = 1; i < s; i++) { e = exp_mod(2, s - i - 1, p); d = exp_mod((r * r % p) * ai % p, e, p); if (d == p - 1) r = r * c % p; c = c * c % p; } return r; } int main(void) { long a, p; printf("x ^ 2 = a mod p\n"); for (;;) { printf("a or 0 to quit = "); scanf("%ld", &a); if (a == 0) break; printf("p = "); scanf("%ld", &p); printf("square_root_mod(%ld, %ld) = %ld\n", a, p, square_root_mod(a, p)); } return 0;

3.44
/* Author:

Algorithm Finding square roots modulo n given its prime factors p and q fsroots.c freelip (3,749)
Pate Williams (c) 1997

The following program determines the square roots of a very long integer modulo a composite very long integer n = p * q where p and q are prime. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al 3.5.1 Section pages 100 - 101, 3.34 Algorithm page 100 and 3.5.2 Section pages 101 - 102 3.44 Algorithm page 102. */ #include #include #include #include #include <assert.h> <ctype.h> <math.h> <stdio.h> "lip.h"

void zsquare_root(verylong za, verylong zp, verylong *zr) { long i, s = 0, t;

verylong zb = 0, zc = 0, zd = 0, ze = 0, zi = 0; verylong zq = 0, zs = 0, zt = 0, zx = 0, zy = 0; if (zcompare(za, zp) < 0) zcopy(za, &ze); else zmod(za, zp, &ze); if (zscompare(ze, 0l) == 0) zzero(zr); else if (zjacobi(ze, zp) == - 1) zzero(zr); else { do zrandomb(zp, &zb); while (zscompare(zb, 0l) == 0 || zjacobi(zb, zp) != - 1); zsadd(zp, - 1l, &zq); zcopy(zq, &zy); do { zrshift(zy, 1l, &zt); s++; t = zodd(zt); zcopy(zt, &zy); } while (!t); zinvmod(ze, zp, &zi); zexpmod(zb, zt, zp, &zc); zsadd(zt, 1l, &zs); zrshift(zs, 1l, &zx); zexpmod(ze, zx, zp, zr); for (i = 1; i < s; i++) { zsq(*zr, &zs); zmulmod(zs, zi, zp, &zx); zsexpmod(zx, pow(2, s - i - 1), zp, &zd); if (zcompare(zd, zq) == 0) { zmulmod(*zr, zc, zp, &zx); zcopy(zx, zr); } zmulmod(zc, zc, zp, &zx); zcopy(zx, &zc); } } zfree(&zb); zfree(&zc); zfree(&zd); zfree(&ze); zfree(&zi); zfree(&zq); zfree(&zs); zfree(&zt); zfree(&zx); } void zsquare_roots(verylong za, verylong zp, verylong zq, verylong *zx1, verylong *zx2, verylong *zy1, verylong *zy2) { verylong zb = 0, zc = 0, zd = 0, ze = 0, zg = 0; verylong zn = 0, zr = 0, zs = 0, zx = 0, zy = 0; verylong zt = 0, zz = 0;

zsquare_root(za, zp, &zr); if (zscompare(zr, 0l) != 0) { zsqrtmod(za, zp, &zx); assert(zcompare(zr, zx) == 0); } zsquare_root(za, zq, &zs); if (zscompare(zs, 0l) != 0) { zsqrtmod(za, zq, &zx); assert(zcompare(zs, zx) == 0); } zexteucl(zp, &zc, zq, &zd, &zg); if (zscompare(zg, 1l) == 0) { zmul(zp, zq, &zn); zmulmod(zr, zd, zn, &zb); zmulmod(zb, zq, zn, &zt); zmulmod(zs, zc, zn, &ze); zmulmod(ze, zp, zn, &zz); zaddmod(zt, zz, zn, &zx); zmulmod(zr, zq, zn, &zb); zmulmod(zs, zc, zn, &ze); zmulmod(ze, zp, zn, &zz); zsubmod(zt, zz, zn, &zy); zmod(zx, zn, zx1); znegate(&zx); zmod(zx, zn, zx2); zmod(zy, zn, zy1); znegate(&zy); zmod(zy, zn, zy2); } else { zzero(zx1); zzero(zx2); zzero(zy1); zzero(zy2); } zfree(&zb); zfree(&zc); zfree(&zd); zfree(&ze); zfree(&zg); zfree(&zn); zfree(&zr); zfree(&zs); zfree(&zt); zfree(&zx); zfree(&zy); zfree(&zz); } int main(void) { char answer[256]; verylong za = 0, zp = 0, zq = 0, zu = 0, zv = 0; verylong zx = 0, zy = 0; do {

printf("enter the number whose square root is sought\n"); zread(&za); printf("enter one of the modulus' prime factors\n"); zread(&zp); printf("enter the other modulus prime factor\n"); zread(&zq); zsquare_roots(za, zp, zq, &zu, &zv, &zx, &zy); printf("the square roots modulo the composite number are:\n"); zwriteln(zu); zwriteln(zv); zwriteln(zx); zwriteln(zy); printf("compute another square root (n or y)? "); scanf("%s", answer); } while (tolower(answer[0]) == 'y'); zfree(&za); zfree(&zp); zfree(&zq); zfree(&zu); zfree(&zv); zfree(&zx); zfree(&zy); return 0;

3.56
/* Author:

Algorithm Baby-step giant-step for computing discrete logarithms dlp.c (5,234)


Pate Williams (c) 1997

The following program implements and tests two algorithms for solving the discrete logarithm problem. The algorithms are baby-step giant-step and Pollard's rho algorithms. The implementations are from "Handbook of Applied Cryptography" by Alfred J. Menezes et al pages 103 - 107. */ #include <stdio.h> #include <stdlib.h> #include "lip.h" struct Element { long index; verylong alpha_index; }; long Find(long n, verylong value, struct Element *array) { long c, hi = n - 1, lo = 0, mid; for (;;) { mid = (hi + lo) / 2; c = zcompare(value, array[mid].alpha_index); if (c == 0) return mid;

} }

if (c < 0) hi = mid - 1; else lo = mid + 1; if (lo > hi) return - 1;

int BabyStepGiantStep(verylong zalpha, verylong zbeta, verylong zn, verylong zp, verylong *zx) /* given a generator alpha of a cyclic group G of order n and an element beta compute the discrete logarithm x returns 0 if not enough memory for the problem 1 otherwise */ { long i, j, m; static verylong za = 0, zd = 0, zg = 0, zm = 0; struct Element *element, temp; zsqrt(zn, &za, &zd); zsadd(za, 1l, &zm); m = ztoint(zm); element = (struct Element *) malloc(m * sizeof(struct Element)); if (element == 0) return 0; zone(&zd); /* construct table */ for (i = 0; i < m; i++) { element[i].index = i; element[i].alpha_index = 0; zcopy(zd, &element[i].alpha_index); zmul(zd, zalpha, &za); zmod(za, zp, &zd); } /* sort on second values */ for (i = 0; i < m - 1; i++) { for (j = i + 1; j < m; j++) { if (zcompare(element[i].alpha_index, element[j].alpha_index) > 0) { temp = element[i]; element[i] = element[j]; element[j] = temp; } } } zinvmod(zalpha, zp, &za); zexp(za, zm, &zg); zmod(zg, zp, &zd); zcopy(zbeta, &zg); for (i = 0; i < m; i++) { printf("%d ", element[i].index); zwriteln(element[i].alpha_index); } for (i = 0; i < m; i++) { j = Find(m, zg, element); if (j != - 1) { zsmul(zm, i, &za); zsadd(za, j, zx); for (j = 0; j < m; j++) zfree(&element[j].alpha_index); free(element);

return 1; } zmul(zg, zd, &za); zmod(za, zp, &zg); } return 0; } void zai(verylong za0, verylong zn, verylong zx0, verylong *za1) { long x = zsmod(zx0, 3l); static verylong za = 0; if (x == 1) zcopy(za0, za1); else if (x == 0) { zsmul(za0, 2l, &za); zmod(za, zn, za1); } else { zsadd(za0, 1l, &za); zmod(za, zn, za1); }

void zbi(verylong zb0, verylong zn, verylong zx0, verylong *zb1) { long x = zsmod(zx0, 3l); static verylong zb = 0; if (x == 1) { zsadd(zb0, 1l, &zb); zmod(zb, zn, zb1); } else if (x == 0) { zsmul(zb0, 2l, &zb); zmod(zb, zn, zb1); } else zcopy(zb0, zb1); } void zfi(verylong zalpha, verylong zbeta, verylong zp, verylong zx0, verylong *zx1) { long x = zsmod(zx0, 3l); if (x == 1) zmulmod(zbeta, zx0, zp, zx1); else if (x == 0) zmulmod(zx0, zx0, zp, zx1); else zmulmod(zalpha, zx0, zp, zx1);

int PollardRho(verylong zalpha, verylong zbeta, verylong zn, verylong zp, verylong *zx)

long i static static static static

= 2, j; verylong verylong verylong verylong

za0 = 0, za1 = 0, za2 = 0, za3 = 0; zb0 = 0, zb1 = 0, zb2 = 0, zb3 = 0; zx0 = 0, zx1 = 0, zx2 = 0, zx3 = 0; zr = 0, zri = 0;

zone(&zx0); zzero(&za0); zzero(&zb0); zfi(zalpha, zbeta, zp, zx0, &zx1); zai(za0, zn, zx0, &za1); zbi(zb0, zn, zx0, &zb1); zfi(zalpha, zbeta, zp, zx1, &zx2); zai(za1, zn, zx1, &za2); zbi(zb1, zn, zx1, &zb2); zcopy(za1, &za0); zcopy(zb1, &zb0); zcopy(zx1, &zx0); for (;;) { zfi(zalpha, zbeta, zp, zx0, &zx1); zai(za0, zn, zx0, &za1); zbi(zb0, zn, zx0, &zb1); zcopy(za1, &za2); zcopy(zb1, &zb2); zcopy(zx1, &zx2); i++; for (j = 0; j < i; j++) { zfi(zalpha, zbeta, zp, zx2, &zx3); zai(za2, zn, zx2, &za3); zbi(zb2, zn, zx2, &zb3); zcopy(za3, &za2); zcopy(zb3, &zb2); zcopy(zx3, &zx2); } if (zcompare(zx1, zx3) == 0) { zsubmod(zb1, zb3, zn, &zr); if (zscompare(zr, 0) == 0) return 0; zinvmod(zr, zn, &zri); zsub(za3, za1, &za0); zmulmod(za0, zri, zn, zx); return 1; } zcopy(za1, &za0); zcopy(zb1, &zb0); zcopy(zx1, &zx0); }

int main(void) { verylong zalpha = 0, zbeta = 0, zn = 0, zp = 0, zx = 0; zintoz(3l, &zalpha); zintoz(57l, &zbeta); zintoz(112l, &zn); zintoz(113l, &zp);

BabyStepGiantStep(zalpha, zbeta, zn, zp, &zx); printf("the discrete logarithm of 57 base 3 = "); zwriteln(zx); zintoz(2l, &zalpha); zintoz(228l, &zbeta); zintoz(191l, &zn); zintoz(383l, &zp); PollardRho(zalpha, zbeta, zn, zp, &zx); printf("the discrete logarithm of 228 base 2 = "); zwriteln(zx); zfree(&zalpha); zfree(&zbeta); zfree(&zn); zfree(&zp); zfree(&zx); return 0; }

3.60
/* Author:

Algorithm Pollard's rho algorithm for computing discrete logarithms dlp.c (5,234)
Pate Williams (c) 1997

*/

The following program implements and tests two algorithms for solving the discrete logarithm problem. The algorithms are baby-step giant-step and Pollard's rho algorithms. The implementations are from "Handbook of Applied Cryptography" by Alfred J. Menezes et al pages 103 - 107.

#include <stdio.h> #include <stdlib.h> #include "lip.h" struct Element { long index; verylong alpha_index; }; long Find(long n, verylong value, struct Element *array) { long c, hi = n - 1, lo = 0, mid; for (;;) { mid = (hi + lo) / 2; c = zcompare(value, array[mid].alpha_index); if (c == 0) return mid; if (c < 0) hi = mid - 1; else lo = mid + 1; if (lo > hi) return - 1; } } int BabyStepGiantStep(verylong zalpha, verylong zbeta,

verylong zn, verylong zp, verylong *zx) /* given a generator alpha of a cyclic group G of order n and an element beta compute the discrete logarithm x returns 0 if not enough memory for the problem 1 otherwise */ { long i, j, m; static verylong za = 0, zd = 0, zg = 0, zm = 0; struct Element *element, temp; zsqrt(zn, &za, &zd); zsadd(za, 1l, &zm); m = ztoint(zm); element = (struct Element *) malloc(m * sizeof(struct Element)); if (element == 0) return 0; zone(&zd); /* construct table */ for (i = 0; i < m; i++) { element[i].index = i; element[i].alpha_index = 0; zcopy(zd, &element[i].alpha_index); zmul(zd, zalpha, &za); zmod(za, zp, &zd); } /* sort on second values */ for (i = 0; i < m - 1; i++) { for (j = i + 1; j < m; j++) { if (zcompare(element[i].alpha_index, element[j].alpha_index) > 0) { temp = element[i]; element[i] = element[j]; element[j] = temp; } } } zinvmod(zalpha, zp, &za); zexp(za, zm, &zg); zmod(zg, zp, &zd); zcopy(zbeta, &zg); for (i = 0; i < m; i++) { printf("%d ", element[i].index); zwriteln(element[i].alpha_index); } for (i = 0; i < m; i++) { j = Find(m, zg, element); if (j != - 1) { zsmul(zm, i, &za); zsadd(za, j, zx); for (j = 0; j < m; j++) zfree(&element[j].alpha_index); free(element); return 1; } zmul(zg, zd, &za); zmod(za, zp, &zg); } return 0; }

void zai(verylong za0, verylong zn, verylong zx0, verylong *za1) { long x = zsmod(zx0, 3l); static verylong za = 0; if (x == 1) zcopy(za0, za1); else if (x == 0) { zsmul(za0, 2l, &za); zmod(za, zn, za1); } else { zsadd(za0, 1l, &za); zmod(za, zn, za1); } } void zbi(verylong zb0, verylong zn, verylong zx0, verylong *zb1) { long x = zsmod(zx0, 3l); static verylong zb = 0; if (x == 1) { zsadd(zb0, 1l, &zb); zmod(zb, zn, zb1); } else if (x == 0) { zsmul(zb0, 2l, &zb); zmod(zb, zn, zb1); } else zcopy(zb0, zb1);

void zfi(verylong zalpha, verylong zbeta, verylong zp, verylong zx0, verylong *zx1) { long x = zsmod(zx0, 3l); if (x == 1) zmulmod(zbeta, zx0, zp, zx1); else if (x == 0) zmulmod(zx0, zx0, zp, zx1); else zmulmod(zalpha, zx0, zp, zx1); } int PollardRho(verylong zalpha, verylong zbeta, verylong zn, verylong zp, verylong *zx) { long i = 2, j; static verylong za0 = 0, za1 = 0, za2 = 0, za3 = 0; static verylong zb0 = 0, zb1 = 0, zb2 = 0, zb3 = 0; static verylong zx0 = 0, zx1 = 0, zx2 = 0, zx3 = 0; static verylong zr = 0, zri = 0;

zone(&zx0); zzero(&za0); zzero(&zb0); zfi(zalpha, zbeta, zp, zx0, &zx1); zai(za0, zn, zx0, &za1); zbi(zb0, zn, zx0, &zb1); zfi(zalpha, zbeta, zp, zx1, &zx2); zai(za1, zn, zx1, &za2); zbi(zb1, zn, zx1, &zb2); zcopy(za1, &za0); zcopy(zb1, &zb0); zcopy(zx1, &zx0); for (;;) { zfi(zalpha, zbeta, zp, zx0, &zx1); zai(za0, zn, zx0, &za1); zbi(zb0, zn, zx0, &zb1); zcopy(za1, &za2); zcopy(zb1, &zb2); zcopy(zx1, &zx2); i++; for (j = 0; j < i; j++) { zfi(zalpha, zbeta, zp, zx2, &zx3); zai(za2, zn, zx2, &za3); zbi(zb2, zn, zx2, &zb3); zcopy(za3, &za2); zcopy(zb3, &zb2); zcopy(zx3, &zx2); } if (zcompare(zx1, zx3) == 0) { zsubmod(zb1, zb3, zn, &zr); if (zscompare(zr, 0) == 0) return 0; zinvmod(zr, zn, &zri); zsub(za3, za1, &za0); zmulmod(za0, zri, zn, zx); return 1; } zcopy(za1, &za0); zcopy(zb1, &zb0); zcopy(zx1, &zx0); } } int main(void) { verylong zalpha = 0, zbeta = 0, zn = 0, zp = 0, zx = 0; zintoz(3l, &zalpha); zintoz(57l, &zbeta); zintoz(112l, &zn); zintoz(113l, &zp); BabyStepGiantStep(zalpha, zbeta, zn, zp, &zx); printf("the discrete logarithm of 57 base 3 = "); zwriteln(zx); zintoz(2l, &zalpha); zintoz(228l, &zbeta); zintoz(191l, &zn); zintoz(383l, &zp);

PollardRho(zalpha, zbeta, zn, zp, &zx); printf("the discrete logarithm of 228 base 2 = "); zwriteln(zx); zfree(&zalpha); zfree(&zbeta); zfree(&zn); zfree(&zp); zfree(&zx); return 0;

3.68
/* Author:

Algorithm Index-calculus algorithm for discrete logarithms in cyclic groups index.c freelip (11,083)
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. <assert.h> <stdio.h> <stdlib.h> <time.h> "lip.h"

#include #include #include #include #include

#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); zx, verylong zy, *za, verylong *zb, *zv) v = gcd(x, y) */ = 0, zD = 0; = 0, zg = 0;

void zbinary_ext_gcd(verylong verylong verylong /* returns a * x + b * y = v, { verylong zA = 0, zB = 0, zC verylong zX = 0, zY = 0, zc 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]);

} } #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);

printf(" "); } zwriteln(zc[i]);

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; }

3.105
/* Author:

Algorithm Solving subset problems using LLL-algorithm knapsack.c (5,373)


Pate Williams (c) 1997

*/

Solution of the subset problem using LLL reduction. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al pages 120 - 121. <math.h> <stdio.h> <stdlib.h> <time.h>

#include #include #include #include

void system_error(char error_message[]) { printf("%s",error_message); exit(1); } double **allocate_real_matrix(long m, long n) { long i; double **p = calloc(m, sizeof(double *)); if (!p) system_error("Failure in allocate_real_matrix()."); for (i = 0; i < m; i++){ p[i]= calloc(n, sizeof(double)); if (!p[i]) system_error("Failure in allocate_real_matrix()."); } return p;

double *allocate_real_vector(long n) { double *p = calloc(n, sizeof(double)); if (!p) system_error("Failure in allocate_real_vector()."); return p;

void free_real_matrix(double **m, long n) { long i; for (i = 0; i < n; i++) free(m[i]); free(m);

void free_real_vector(double *v) { free(v); }

double Scalar(long n, double *u, double *v) { double sum = 0.0; long i; for (i = 0; i < n; i++) sum += u[i] * v[i]; return sum; } void Reduce(long k, long l, long n, double **b, double **mu) { long i, j, r = 0.5 + mu[k][l]; if (fabs(mu[k][l]) > 0.5) { for (i = 0; i < n; i++) b[k][i] -= r * b[l][i]; for (j = 0; j < l; j++) mu[k][j] -= r * mu[l][j]; mu[k][l] -= r; }

int LLL(long n, double **b) { /* Lattice reduction algorithm. */ double *B = allocate_real_vector(n); double **bs = allocate_real_matrix(n, n); double **mu = allocate_real_matrix(n, n); double C, t, temp, x, y; long i, j, k, l; for (i = 0; i < n; i++) bs[0][i] = b[0][i]; B[0] = Scalar(n, bs[0], bs[0]); for (i = 1; i < n; i++) { for (j = 0; j < n; j++) bs[i][j] = b[i][j]; for (j = 0; j < i; j++) { mu[i][j] = Scalar(n, b[i], bs[j]) / B[j]; for (k = 0; k < n; k++) bs[i][k] -= mu[i][j] * bs[j][k]; } B[i] = Scalar(n, bs[i], bs[i]); } L3: k = 1; L4: l = k - 1; Reduce(k, l, n, b, mu); x = mu[k][l]; y = 0.75 - x * x; if (B[k] < y * B[l]) { C = B[k] + x * x * B[l]; mu[k][l] = x * B[l] / C; B[k] *= B[l] / C; B[l] = C; for (i = 0; i < n; i++) { temp = b[k][i]; b[k][i] = b[l][i]; b[l][i] = temp;

} for (l = k - 2; l >= 0; l--) Reduce(k, l, n, b, mu); k++; if (k < n) goto L4; free_real_matrix(bs, n); free_real_matrix(mu, n); free_real_vector(B); return 1;

} if (k > 1) { for (j = 0; j < k - 1; j++) { temp = mu[k][j]; mu[k][j] = mu[l][j]; mu[l][j] = temp; } } for (i = k + 1; i < n; i++) { t = mu[i][k]; mu[i][k] = mu[i][l] - x * t; mu[i][l] = t + mu[k][l] * mu[i][k]; } k = max(1, k - 1); goto L4;

int SubsetSum(long n, double s, double *a, double *x) { long n1 = n + 1; double **b = allocate_real_matrix(n1, n1); double sum; long i, j, m = ceil(sqrt(n) / 2.0); for (i = 0; i < n1; i++) { if (i < n) { for (j = 0; j < n1; j++) b[i][j] = 0.0; b[i][i] = 1.0; b[i][n1 - 1] = m * a[i]; } else { for (j = 0; j < n; j++) b[i][j] = 0.5; b[i][n1 - 1] = m * s; } } printf("the matrix to be reduced is:\n\n"); for (i = 0; i < n1; i++) { for (j = 0; j < n1; j++) printf("%6.2f ", b[i][j]); printf("\n"); } printf("\n"); if (!LLL(n1, b)) { free_real_matrix(b, n1); return 0; } printf("the reduced matrix is:\n\n"); for (i = 0; i < n1; i++) { for (j = 0; j < n1; j++)

printf("%6.2f ", b[i][j]); printf("\n"); } printf("\n"); for (i = 0; i < n1; i++) { for (j = 0; j < n; j++) x[j] = sum = 0.0; for (j = 0; j < n; j++) sum += if (sum == s) { free_real_matrix(b, n1); return 1; } for (j = 0; j < n; j++) x[j] = sum = 0.0; for (j = 0; j < n; j++) sum += if (sum == s) { free_real_matrix(b, n1); return 1; } } free_real_matrix(b, n1); return 0; } int main(void) { long i, n = 8; double *a = allocate_real_vector(n); double *x = allocate_real_vector(n); double s; srand(time(NULL)); printf("\n"); for (i = 0; i < n; i++) a[i] = pow(2, i); s = a[rand() % n] + a[rand() % n]; if (SubsetSum(n, s, a, x)) { printf("sum: %f\n\n", s); printf("x[i]\t\ta[i]\n\n"); for (i = 0; i < n; i++) printf("%f\t%f\n", x[i], a[i]); } else printf("subset sum has no solution\n"); free_real_vector(a); free_real_vector(x); return 0;

b[i][j] + 0.5; a[j] * x[j];

- b[i][j] + 0.5; a[j] * x[j];

3.108
/* Author:

Algorithm Finding a delta-quality simultaneous diophantine approximation intlll.c (9,120)


Pate Williams (c) 1997

"Algorithm 2.6.7 (Integral LLL Algorithm). Given a basis b[1], b[2],..., b[n] of a lattice (L, q) by its gram matrix which is assumed to have inte-

gral coefficients, this algorithm transforms the vectors b[i] so that when the algorithm terminates, the b[i] form an LLL-reduced basis." -Henri CohenSee "A Course in Computational Algebraic Number Theory" by Henri Cohen page 94. Also see "Handbook of Applied Cryptography by Alfred J. Menezes et al 3.108 Algorithm "Finding a delta-quality simultaneous diophantine approximation" pages 121-122. */ #include #include #include #include <math.h> <stdio.h> <stdlib.h> "lip.h"

void system_error(char error_message[]) { fprintf(stderr, "%s", error_message); exit(1); } verylong **allocate_very_matrix(long lr, long ur, long lc, long uc) { /* Allocates a real matrix of range [lr..ur][lc..uc]. */ long i; verylong **p = calloc((ur - lr + 1), sizeof(verylong *)); if (!p) system_error("Failure in allocate_very_matrix()."); p -= lr; for (i = lr; i <= ur; i++) { p[i]= calloc((uc - lc + 1), sizeof(verylong)); if (!p[i]) system_error("Failure in allocate_very_matrix()."); p[i] -= lc; } return p; } verylong *allocate_very_vector(long l, long u) { /* Allocates a verylong vector of range [l..u]. */ verylong *p; p = calloc((u - l + 1), sizeof(verylong)); if (!p) system_error("Failure in allocate_very_vector()."); return p - l;

void free_very_matrix(verylong **m, long lr, long ur, long lc, long uc) { /* Frees a verylong matrix of range [lr..ur][lc..uc]. */ long i, j;

for (i = lr; i <= ur; i++) for (j = lc; j <= uc; j++) zfree(&m[i][j]); for (i = ur; i >= lr; i--) free((char *)(m[i] + lc)); free((char *) (m + lr)); } void free_very_vector(verylong *v, long l, long u) { /* Frees a verylong vector of range [l..u]. */ long i; for (i = l; i <= u; i++) zfree(&v[i]); free((char *)(v + l));

void scalar(long n, verylong *za, verylong *zb, verylong *zs) { /* *s = inner_product(a, b) */ long i; verylong zt = 0, zu = 0; zzero(zs); for (i = 1; i <= n; i++) { zmul(za[i], zb[i], &zt); zadd(zt, *zs, &zu); zcopy(zu, zs); } zfree(&zt); zfree(&zu); } void RED(long k, long l, long n, verylong *zd, verylong **zb, verylong **zh, verylong **zl) { long i; verylong zq = 0, zr = 0, zs = 0, zt = 0; zlshift(zl[k][l], 1l, &zr); zcopy(zr, &zs); zabs(&zs); if (zcompare(zs, zd[l]) > 0) { zadd(zr, zd[l], &zs); zlshift(zd[l], 1l, &zr); zdiv(zs, zr, &zq, &zt); for (i = 1; i <= n; i++) { zmul(zq, zh[i][l], &zr); zsub(zh[i][k], zr, &zs); zcopy(zs, &zh[i][k]); zmul(zq, zb[l][i], &zr); zsub(zb[k][i], zr, &zs); zcopy(zs, &zb[k][i]); } zmul(zq, zd[l], &zr);

} zfree(&zq); zfree(&zr); zfree(&zs); zfree(&zt); }

zsub(zl[k][l], zr, &zs); zcopy(zs, &zl[k][l]); for (i = 1; i <= l - 1; i++) { zmul(zq, zl[l][i], &zr); zsub(zl[k][i], zr, &zs); zcopy(zs, &zl[k][i]); }

void SWAP(long k, long k1, long kmax, long n, verylong *zd, verylong **zb, verylong **zh, verylong **zl) { long i, j; verylong zB = 0, zm = 0, zr = 0, zs = 0, zt = 0; verylong zu = 0; for (i = 1; i <= n; i++) { zcopy(zh[i][k], &zt); zcopy(zh[i][k1], &zh[i][k]); zcopy(zt, &zh[i][k1]); } for (j = 1; j <= n; j++) { zcopy(zb[k][j], &zt); zcopy(zb[k1][j], &zb[k][j]); zcopy(zt, &zb[k1][j]); } if (k > 2) { for (j = 1; j <= k - 2; j++) { zcopy(zl[k][j], &zt); zcopy(zl[k1][j], &zl[k][j]); zcopy(zt, &zl[k1][j]); } } zcopy(zl[k][k1], &zm); zmul(zd[k - 2], zd[k], &zr); zsq(zm, &zs); zadd(zr, zs, &zt); zdiv(zt, zd[k1], &zB, &zr); for (i = k + 1; i <= kmax; i++) { zcopy(zl[i][k], &zt); zmul(zd[k], zl[i][k1], &zr); zmul(zm, zt, &zs); zsub(zr, zs, &zu); zdiv(zu, zd[k1], &zl[i][k], &zr); zmul(zB, zt, &zr); zmul(zm, zl[i][k], &zs); zadd(zr, zs, &zu); zdiv(zu, zd[k], &zl[i][k1], &zr); } zcopy(zB, &zd[k1]); zfree(&zB);

zfree(&zm); zfree(&zr); zfree(&zs); zfree(&zt); zfree(&zu);

void int_LLL(long n, verylong **zb, verylong **zh) { double x, y; long i, j, k = 2, k1, kmax = 1, l; verylong zr = 0, zs = 0, zt = 0, zu = 0; verylong *zB = allocate_very_vector(1, n); verylong *zd = allocate_very_vector(0, n); verylong **zl = allocate_very_matrix(1, n, 1, n); zone(&zd[0]); scalar(n, zb[1], zb[1], &zd[1]); for (i = 1; i <= n; i++) { for (j = 1; j <= n; j++) zzero(&zh[i][j]); zone(&zh[i][i]); } #ifdef DEBUG if (n <= 17) { printf("the basis to be reduced is:\n"); for (i = 1; i <= n; i++) { for (j = 1; j <= n; j++) { zwrite(zb[i][j]); printf(" "); } printf("\n"); } } #endif L2: if (k <= kmax) goto L3; kmax = k; for (j = 1; j <= k; j++) { scalar(n, zb[k], zb[j], &zu); for (i = 1; i <= j - 1; i++) { zmul(zd[i], zu, &zr); zmul(zl[k][i], zl[j][i], &zs); zsub(zr, zs, &zt); zdiv(zt, zd[i - 1], &zu, &zr); } if (j < k) zcopy(zu, &zl[k][j]); else if (j == k) { zcopy(zu, &zd[k]); if (zscompare(zd[k], 0l) == 0) system_error("Failure in int_LLL."); } } L3: k1 = k - 1; RED(k, k1, n, zd, zb, zh, zl); zmul(zd[k], zd[k - 2], &zr);

zsq(zd[k1], &zs); zsq(zl[k][k1], &zt); x = zdoub(zr); y = 3.0 * zdoub(zs) / 4.0 - zdoub(zt); if (x < y) { SWAP(k, k1, kmax, n, zd, zb, zh, zl); k = max(2, k1); goto L3; } for (l = k - 2; l >= 1; l--) RED(k, l, n, zd, zb, zh, zl); if (++k <= n) goto L2; #ifdef DEBUG if (n <= 17) { printf("the LLL-reduced basis is:\n"); for (i = 1; i <= n; i++) { for (j = 1; j <= n; j++) { zwrite(zb[i][j]); printf(" "); } printf("\n"); } } #endif free_very_matrix(zl, 1, n, 1, n); free_very_vector(zB, 1, n); free_very_vector(zd, 0, n); zfree(&zr); zfree(&zs); zfree(&zt); zfree(&zu);

int simultaneous_diophantine(double delta, long n, verylong zQ, verylong *zP, verylong *zp, verylong *zq) { double P, Q, l; int equal, found; long i, j, n1 = n + 1; verylong zd = 0, zl = 0, zr = 0, zs = 0, zt = 0; verylong **zA = allocate_very_matrix(1, n1, 1, n1); verylong **zh = allocate_very_matrix(1, n1, 1, n1); Q = zdoub(zQ); zintoz(pow(Q, delta), &zl); l = 1.0 / zdoub(zl); zmul(zl, zQ, &zd); for (i = 1; i <= n; i++) zcopy(zd, &zA[i][i]); znegate(&zl); for (i = 1; i <= n; i++) zmul(zl, zq[i], &zA[n1][i]); zone(&zA[n1][n1]);

int_LLL(n1, zA, zh); found = 0; for (j = 1; !found && j <= n1; j++) { zcopy(zA[j][n1], zP); if (zcompare(*zP, zQ) != 0) { for (i = 1; i <= n; i++) { zdiv(zA[j][i], zl, &zr, &zs); zmul(*zP, zq[i], &zt); zadd(zr, zt, &zs); zdiv(zs, zQ, &zp[i], &zr); } P = zdoub(*zP); #ifdef DEBUG if (n <= 16) { printf("p = "); zwrite(*zP); printf(" p[i] "); for (i = 1; i <= n; i++) { zwrite(zp[i]); printf(" "); } printf("\n"); } #endif if (zcompare(*zP, 0) != 0) { equal = 1; for (i = 1; equal && i <= n; i++) equal = fabs(P * zdoub(zq[i]) / Q - zdoub(zp[i])) <= l; } else equal = 0; found = equal; } } free_very_matrix(zA, 1, n1, 1, n1); free_very_matrix(zh, 1, n1, 1, n1); zfree(&zd); zfree(&zl); zfree(&zr); zfree(&zs); zfree(&zt); return found; } int main(void) { double delta = 0.15; long i, n = 16; verylong zP = 0, zQ = 0; verylong *zp = allocate_very_vector(1, n); verylong *zq = allocate_very_vector(1, n); zpstart2(); for (i = 1; i <= n; i++) zintoz(zpnext(), &zq[i]); zintoz(zpnext(), &zQ); printf("delta = %lf\n", delta);

printf("n = %ld\n", n); if (n <= 16) { printf("q = "); zwriteln(zQ); printf("q[i] "); for (i = 1; i <= n; i++) { zwrite(zq[i]); printf(" "); } } printf("\n"); if (simultaneous_diophantine(delta, n, zQ, &zP, zp, zq)) { printf("p = "); zwriteln(zP); printf("p[i] "); for (i = 1; i <= n; i++) { zwrite(zp[i]); printf(" "); } } else printf("\nno simultaneous diophantine approximation\n"); free_very_vector(zp, 1, n); free_very_vector(zq, 1, n); return 0; }

3.111
/* Author:

Algorithm Berlekamp's Q-matrix algorithm for factoring polynomials over finte fields polyfact.c freelip (12,831)
Pate Williams (c) 1997

Berlekamp's Q-matrix algorithm. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al 3.11.2 Section 3.111 Algorithm page 124. Also see "Seminumerical Algorithms" by Donald E. Knuth second edition page 423 and "A Course in Computational Algebraic Number Theory" by Henri Cohen Algorithm 3.4.10 page 132. */ #include #include #include #include <assert.h> <malloc.h> <stdio.h> "lip.h"

#define DEBUG #define POLY_SIZE 8192l verylong **create_matrix(long m, long n) { long i; verylong **matrix = calloc(m, sizeof(verylong)); assert(matrix != 0); for (i = 0; i < m; i++) {

matrix[i] = calloc(n, sizeof(verylong)); assert(matrix[i] != 0); } return matrix; } void delete_matrix(long m, verylong **matrix) { long i; for (i = 0; i < m; i++) free(matrix[i]); free(matrix); } void zpoly_mul(long m, long n, verylong *za, verylong *zb, verylong *zc, long *p) { long i, j, k; verylong zd = 0, zai = 0, zbk = 0, zsum = 0, zterm = 0; *p = m + n; for (k = 0; k <= *p; k++) { zzero(&zsum); for (i = 0; i <= k; i++) { j = k - i; if (i > m) zzero(&zai); else zcopy(za[i], &zai); if (j > n) zzero(&zbk); else zcopy(zb[j], &zbk); zmul(zai, zbk, &zterm); zcopy(zsum, &zd); zadd(zterm, zd, &zsum); } zcopy(zsum, &zc[k]); } zfree(&zd); zfree(&zai); zfree(&zbk); zfree(&zsum); zfree(&zterm); } void zpoly_div(long m, long n, verylong *zu, verylong *zv, verylong *zq, verylong *zr, long *p, long *s) { long j, jk, k, nk; verylong za = 0, zb = 0, zvn = 0; zcopy(zv[n], &zvn); for (j = 0; j <= m; j++) zcopy(zu[j], &zr[j]); if (m < n) { *p = 0, *s = m; zzero(&zq[0]); } else { *p = m - n, *s = n - 1;

} zfree(&za); zfree(&zb); zfree(&zvn);

for (k = *p; k >= 0; k--) { nk = n + k; zsexp(zvn, k, &za); zmul(zr[nk], za, &zq[k]); for (j = nk - 1; j >= 0; j--) { jk = j - k; if (jk >= 0) { zmul(zvn, zr[j], &za); zmul(zr[nk], zv[jk], &zb); zsub(za, zb, &zr[j]); } else { zcopy(zr[j], &za); zmul(zvn, za, &zr[j]); } } } while (*p > 0 && zscompare(zq[*p], 0l) == 0) *p = *p - 1; while (*s > 0 && zscompare(zr[*s], 0l) == 0) *s = *s - 1;

void zpoly_mod(long p, verylong *za, long *da) { long i; for (i = 0; i <= *da; i++) zintoz(zsmod(za[i], p), &za[i]); while (*da > 0 && zscompare(za[*da], 0l) == 0) *da = *da - 1; } void zpoly_pow(long degreeA, long degreem, long p, verylong zn, verylong *zA, verylong *zm, verylong *zs, long *ds) { long dp, dq, dx = degreeA, i; verylong za = 0, zb = 0, zp[POLY_SIZE], zq[POLY_SIZE], zx[POLY_SIZE], zy[POLY_SIZE]; for (i = 0; i < POLY_SIZE; i++) zp[i] = zq[i] = zx[i] = zy[i] = 0; *ds = 0; zcopy(zn, &za); zone(&zs[0]); for (i = 0; i <= dx; i++) zcopy(zA[i], &zx[i]); while (zscompare(za, 0l) > 0) { if (zodd(za)) { /* s = (s * x) % m; */ zpoly_mul(*ds, dx, zs, zx, zp, &dp); zpoly_div(dp, degreem, zp, zm, zq, zs, &dq, ds); zpoly_mod(p, zs, ds); } zcopy(za, &zb);

zrshift(zb, 1l, &za); if (zscompare(za, 0l) > 0) { /* x = (x * x) % m; */ for (i = 0; i <= dx; i++) zcopy(zx[i], &zy[i]); zpoly_mul(dx, dx, zx, zy, zp, &dp); zpoly_div(dp, degreem, zp, zm, zq, zx, &dq, &dx); zpoly_mod(p, zx, &dx); } } zfree(&za); zfree(&zb); for (i = 0; i < POLY_SIZE; i++) { zfree(&zp[i]); zfree(&zq[i]); zfree(&zx[i]); zfree(&zy[i]); }

void zpoly_sub(long da, long db, verylong *za, verylong *zb, verylong *zc, long *dc) { long i; verylong zz = 0; zzero(&zz); if (da >= db) { for (i = 0; i <= db; i++) zsub(za[i], zb[i], &zc[i]); for (i = db + 1; i <= da; i++) zcopy(za[i], &zc[i]); *dc = da; } else { for (i = 0; i <= da; i++) zsub(za[i], zb[i], &zc[i]); for (i = da + 1; i <= db; i++) zsub(zz, zb[i], &zc[i]); *dc = db; } zfree(&zz);

void zpoly_gcd(long degreeA, long degreeB, long p, verylong *zA, verylong *zB, verylong *za, long *da) { int nonzero = 0, zero; long db, dq, dr, i; verylong zc = 0, zd = 0, zp = 0; verylong zb[POLY_SIZE], zq[POLY_SIZE], zr[POLY_SIZE]; for (i = 0; i < POLY_SIZE; i++) zb[i] = zq[i] = zr[i] = 0; if (degreeA > degreeB) { *da = degreeA; db = degreeB;

for (i = 0; i <= *da; i++) zcopy(zA[i], &za[i]); for (i = 0; i <= db; i++) zcopy(zB[i], &zb[i]); } else { *da = degreeB; db = degreeA; for (i = 0; i <= *da; i++) zcopy(zB[i], &za[i]); for (i = 0; i <= db; i++) zcopy(zA[i], &zb[i]); } for (i = 0; i <= db && !nonzero; i++) nonzero = zscompare(zb[i], 0l) != 0; zintoz(p, &zp); while (nonzero) { zpoly_div(*da, db, za, zb, zq, zr, &dq, &dr); for (i = 0; i <= dr; i++) { zcopy(zr[i], &zc); zmod(zc, zp, &zr[i]); } zero = 1; for (i = dr; i >= 0 && zero; i--) { zero = zscompare(zr[i], 0l) == 0; if (zero && dr > 0) dr--; } for (i = 0; i <= db; i++) zcopy(zb[i], &za[i]); *da = db; for (i = 0; i <= dr; i++) zcopy(zr[i], &zb[i]); db = dr; nonzero = 0; for (i = 0; i <= db && !nonzero; i++) nonzero = zscompare(zb[i], 0l) != 0; } if (*da > 0) { zinvmod(za[*da], zp, &zd); for (i = 0; i <= *da; i++) { zmulmod(za[i], zd, zp, &zc); zcopy(zc, &za[i]); } } zfree(&zc); zfree(&zd); zfree(&zp); for (i = 0; i < POLY_SIZE; i++) { zfree(&zb[i]); zfree(&zq[i]); zfree(&zr[i]); } } void zpoly_copy(long da, verylong *za, verylong *zb, long *db) { long i; *db = da; for (i = 0; i <= da; i++) zcopy(za[i], &zb[i]); } void zpoly_print(long da, verylong *za)

long i; for (i = da; i >= 0; i--) { zwrite(za[i]); printf(" "); } printf("\n");

} void zpoly_ext_euclid(long dg, long dh, long p, verylong *zg, verylong *zh, verylong *zs, verylong *zt, verylong *zd, long *ds, long *dt, long *dd) { long da, dq, dr, ds1 = 0, ds2 = 0, dt1 = 0, dt2 = 0, i; verylong za[POLY_SIZE], zb[POLY_SIZE]; verylong zq[POLY_SIZE], zr[POLY_SIZE]; verylong zs1[POLY_SIZE], zs2[POLY_SIZE]; verylong zt1[POLY_SIZE], zt2[POLY_SIZE]; if (dh == 0 && zscompare(zh[0], 0l) == 0) { zpoly_copy(dg, zg, zd, dd); *ds = *dt = 0; zone(&zs[0]); zzero(&zt[0]); } for (i = 0; i < POLY_SIZE; i++) { za[i] = zb[i] = zq[i] = zr[i] = 0; zs1[i] = zs2[i] = zt1[i] = zt2[i] = 0; } zone(&zs2[0]); zzero(&zs1[0]); zzero(&zt2[0]); zone(&zt1[0]); while (dh != 0 || zscompare(zh[0], 0l) != 0) { zpoly_div(dg, dh, zg, zh, zq, zr, &dq, &dr); zpoly_mod(p, zq, &dq); zpoly_mod(p, zr, &dr); zpoly_mul(dq, ds1, zq, zs1, za, &da); zpoly_sub(ds2, da, zs2, za, zs, ds); zpoly_mul(dq, dt1, zq, zt1, za, &da); zpoly_sub(dt2, da, zt2, za, zt, dt); zpoly_mod(p, zs, ds); zpoly_mod(p, zt, dt); zpoly_copy(dh, zh, zg, &dg); zpoly_copy(dr, zr, zh, &dh); zpoly_copy(ds1, zs1, zs2, &ds2); zpoly_copy(*ds, zs, zs1, &ds1); zpoly_copy(dt1, zt1, zt2, &dt2); zpoly_copy(*dt, zt, zt1, &dt1); #ifdef DEBUG printf("q = "); zpoly_print(dq, zq); printf("r = "); zpoly_print(dr, zr); printf("s = "); zpoly_print(*ds, zs); printf("t = "); zpoly_print(*dt, zt); printf("g = "); zpoly_print(dg, zg);

printf("h printf("s2 printf("s1 printf("t2 printf("t1 #endif

= = = = =

"); "); "); "); ");

zpoly_print(dh, zh); zpoly_print(ds2, zs2); zpoly_print(ds1, zs1); zpoly_print(dt2, zt2); zpoly_print(dt1, zt1);

} zpoly_copy(dg, zg, zd, dd); zpoly_copy(ds2, zs2, zs, ds); zpoly_copy(dt2, zt2, zt, dt); for (i = 0; i < POLY_SIZE; i++) { zfree(&za[i]); zfree(&zb[i]); zfree(&zq[i]); zfree(&zr[i]); zfree(&zs1[i]); zfree(&zs2[i]); zfree(&zt1[i]); zfree(&zt2[i]); } } void kernel(long m, long n, long p, verylong **zM, verylong **zX, long *r) { int found; long *c = calloc(m, sizeof(long)), i, j, k, s; verylong zD = 0, za = 0, zb = 0, zp = 0; assert(c != 0); zintoz(p, &zp); *r = 0; for (i = 0; i < m; i++) c[i] = - 1; for (k = 0; k < m; k++) { found = 0, j = 0; while (!found && j < m) { found = zscompare(zM[k][j], 0l) != 0 && c[j] < 0; if (!found) j++; } if (found) { zinvmod(zM[k][j], zp, &zD); znegate(&zD); zintoz(- 1l, &zM[k][j]); for (s = k + 1; s < m; s++) { zmul(zD, zM[s][j], &za); zmod(za, zp, &zM[s][j]); } for (i = 0; i < n; i++) { if (i != j) { zcopy(zM[k][i], &zD); zzero(&zM[k][i]); for (s = k + 1; s < m; s++) { zmul(zD, zM[s][j], &za); zadd(zM[s][i], za, &zb); zmod(zb, zp, &zM[s][i]); }

} else { for (j = 0; j < n; j++) zzero(&zX[*r][j]); for (j = 0; j < n; j++) { for (s = 0; s < n; s++) { if (j == k) zone(&zX[*r][j]); else if (c[s] == j) zcopy(zM[k][s], &zX[*r][j]); } } *r = *r + 1; } } free(c); zfree(&zD); zfree(&za); zfree(&zb); zfree(&zp); } void Berlekamp_algorithm(long n, long p, verylong *zu, verylong **zc, long *count) { long da, db, dw, i, index = 0, j, k, s, r; verylong zd = 0, zn = 0, zp = 0; verylong za[POLY_SIZE], zb[POLY_SIZE]; verylong zw[POLY_SIZE], zX[POLY_SIZE]; verylong **zq = create_matrix(n, n), **zv = create_matrix(n, n); for (i = 0; i < POLY_SIZE; i++) za[i] = zb[i] = zw[i] = zX[i] = 0; zone(&zq[0][0]); zzero(&zX[0]); zone(&zX[1]); for (k = 1; k < n; k++) zzero(&zq[0][k]); zintoz(p, &zp); for (k = 1; k < n; k++) { zsmul(zp, k, &zn); zpoly_pow(1l, n, p, zn, zX, zu, za, &da); for (j = 0; j < n; j++) zcopy(za[j], &zq[k][j]); } #ifdef DEBUG printf("the Q-matrix is as follows:\n\n"); for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { zwrite(zq[i][j]); printf(" "); } printf("\n"); } printf("\n"); #endif for (i = 0; i < n; i++) { zsadd(zq[i][i], - 1l, &zd);

} } c[j] = k;

zcopy(zd, &zq[i][i]); } kernel(n, n, p, zq, zv, &r); #ifdef DEBUG printf("the linearly independent vectors are as follows:\n\n"); for (i = 0; i < r; i++) { for (j = 0; j < n; j++) { zwrite(zv[i][j]); printf(" "); } printf("\n"); } printf("\n"); #endif for (i = 0; i <= n; i++) zcopy(zu[i], &zw[i]); dw = n; *count = 0; for (i = 1; i < r; i++) { for (s = 0; s < p; s++) { for (j = 0; j < n; j++) zcopy(zv[i][j], &za[j]); zsadd(za[0], - s, &zd); zcopy(zd, &za[0]); da = n - 1; while (da > 0 && zscompare(za[da], 0l) == 0) da--; zpoly_gcd(da, dw, p, za, zw, zb, &db); if (db != 0) { for (j = 0; j <= db; j++) zcopy(zb[j], &zc[*count][j]); *count = *count + 1; } } for (j = 0; j < n; j++) zcopy(zc[index][j], &zw[j]); index++; dw = n - 1, j = dw; while (dw > 0) if (zscompare(zw[j--], 0l) == 0) dw--; else break; } delete_matrix(n, zq); delete_matrix(n, zv); zfree(&zd); zfree(&zn); zfree(&zp); for (i = 0; i < POLY_SIZE; i++) { zfree(&za[i]); zfree(&zb[i]); zfree(&zw[i]); zfree(&zX[i]); } } int main(void) { long i, j, n = 8, p = 13l, r; verylong zu[POLY_SIZE]; verylong **zX = create_matrix(8, 8);

for (i = 0; i < POLY_SIZE; i++) zu[i] = 0; zone(&zu[8]); zone(&zu[6]); zintoz(10l, &zu[4]); zintoz(10l, &zu[3]); zintoz(8l, &zu[2]); zintoz(2l, &zu[1]); zintoz(8l, &zu[0]); printf("u = "); zpoly_print(n, zu); printf("\n"); Berlekamp_algorithm(n, p, zu, zX, &r); printf("the linear independent polynomials are as follows:\n\n"); for (i = 0; i < r; i++) { for (j = 0; j < n; j++) { zwrite(zX[i][j]); printf(" "); } printf("\n"); } delete_matrix(8, zX); for (i = 0; i < POLY_SIZE; i++) zfree(&zu[i]); return 0;

Chapter 04
4.9 4.18 4.24 4.53 4.69 4.9
/* Author:

Public-Key Parameters

Algorithm Fermat primality test fermat.c freelip (1,304) Algorithm Solovay-Strassen probabilistic primality test solovay.c freelip (1,665) Algorithm Miller-Rabin probabilistic primality test miller.c freelip (1,832) Algorithm Gordon's algorithm for generating a strong prime gordon.c freelip (1,676) Algorithm Testing a polynomial for irreducibility genirred.c freelip (7,086) Algorithm Fermat primality test fermat.c freelip (1,304)
Pate Williams (c) 1997

*/

4.9 Algorithm Fermat primality test. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al page 136.

#include <ctype.h>

#include <stdio.h> #include "lip.h" int Fermat(long t, verylong zn) /* returns 0 if composite 1 if probably prime */ { int flag = 1; long i; verylong za = 0, zn1 = 0, zr = 0; if (zodd(zn)) { if (zscompare(zn, 3l) > 0) { zsadd(zn, - 1l, &zn1); for (i = 1; flag && i <= t; i++) { do zrandomb(zn1, &za); while (zscompare(za, 2l) < 0); zexpmod(za, zn1, zn, &zr); if (zscompare(zr, 1l) != 0) flag = 0; } } } else flag = zscompare(zn, 2l) == 0; zfree(&za); zfree(&zn1); zfree(&zr); return flag;

int main(void) { char answer[256]; long t; verylong zn = 0; do { do { printf("enter the security parameter ( >= 1): "); scanf("%d", &t); } while (t < 1); printf("enter the number to be tested below:\n"); zread(&zn); if (Fermat(t, zn)) printf("number is probably prime\n"); else printf("number is composite\n"); printf("another number (n or y)? "); scanf("%s", answer); } while (tolower(answer[0]) == 'y'); zfree(&zn); return 0;

4.18
/*

Algorithm Solovay-Strassen probabilistic primality test solovay.c freelip (1,665)

Author:

Pate Williams (c) 1997

4.18 Algorithm Solovay-Strassen probabilistic primality test. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al page 138. */ #include <ctype.h> #include <stdio.h> #include "lip.h" int Solovay_Strassen(long t, verylong zn) { int flag = 1; long i; verylong za = 0, zn1 = 0, zn2 = 0, zr = 0; verylong zs = 0, zt = 0; if (zodd(zn)) { if (zscompare(zn, 3l) > 0) { zsadd(zn, - 1l, &zn1); zrshift(zn1, 1l, &zn2); for (i = 1; flag && i <= t; i++) { do zrandomb(zn1, &za); while (zscompare(za, 2l) < 0); zexpmod(za, zn2, zn, &zr); if (zscompare(zr, 1l) != 0 && zcompare(zr, zn1) != 0) flag = 0; zintoz(zjacobi(za, zn), &zs); if (zscompare(zs, 0l) < 0) { zadd(zs, zn, &zt); zcopy(zt, &zs); } if (flag && zcompare(zr, zs) != 0) flag = 0; } } } else flag = zscompare(zn, 2l) == 0; zfree(&za); zfree(&zn1); zfree(&zn2); zfree(&zr); zfree(&zs); zfree(&zt); return flag; } int main(void) { char answer[256]; long t; verylong zn = 0; do { do { printf("enter the security parameter ( >= 1): ");

scanf("%d", &t); } while (t < 1); printf("enter the number to be tested below:\n"); zread(&zn); if (Solovay_Strassen(t, zn)) printf("number is probably prime\n"); else printf("number is composite\n"); printf("another number (n or y)? "); scanf("%s", answer); } while (tolower(answer[0]) == 'y'); zfree(&zn); return 0;

4.24
/* Author:

Algorithm Miller-Rabin probabilistic primality test miller.c freelip (1,832)


Pate Williams (c) 1997

*/

4.24 Algorithm Miller-Rabin probabilistic primality test. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al page 139.

#include <ctype.h> #include <stdio.h> #include "lip.h" int Miller_Rabin(long t, verylong zn) { int value = 1; long i, j, s = 0; verylong za = 0, zb = 0, zn1 = 0, zr = 0, zy = 0; if (zodd(zn)) { if (zscompare(zn, 3l) > 0) { zsadd(zn, - 1l, &zn1); zcopy(zn1, &zr); while (!zodd(zr)) { s++; zrshift(zr, 1l, &za); zcopy(za, &zr); } for (i = 1; value && i <= t; i++) { do zrandomb(zn1, &za); while (zscompare(za, 2l) < 0); zexpmod(za, zr, zn, &zy); if (zscompare(zy, 1l) != 0 && zcompare(zy, zn1) != 0) { j = 1; while (value && j <= s - 1 && zcompare(zy, zn1) != 0) { zmulmod(zy, zy, zn, &zb); zcopy(zb, &zy); if (zscompare(zy, 1l) == 0) value = 0; j++;

} if (value && zcompare(zy, zn1) != 0) value = 0; } } } else value = 1; } else value = zscompare(zn, 2l) == 0; zfree(&za); zfree(&zb); zfree(&zn1); zfree(&zr); zfree(&zy); return value; } int main(void) { char answer[256]; long t; verylong zn = 0; do { do { printf("enter the security parameter ( >= 1): "); scanf("%d", &t); } while (t < 1); printf("enter the number to be tested below:\n"); zread(&zn); if (Miller_Rabin(t, zn)) printf("number is probably prime\n"); else printf("number is composite\n"); printf("another number (n or y)? "); scanf("%s", answer); } while (tolower(answer[0]) == 'y'); zfree(&zn); return 0; }

4.53
/* Author:

Algorithm Gordon's algorithm for generating a strong prime gordon.c freelip (1,676)
Pate Williams (c) 1997

Gordon's algorithm for generating strong primes. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al 4.53 Algorithm page 150. */ #include #include #include #include <stdio.h> <stdlib.h> <time.h> "lip.h"

long Gordon(long bit_length, verylong *zp) { long i, i0, j, k, j0, s_size = bit_length / 2; verylong za = 0, zb = 0, zc = 0, zr = 0; verylong zs = 0, zt = 0, zp0 = 0; zrstarts(time(NULL)); zrandomprime(s_size, 5l, &zs, zrandomb); zrandomprime(s_size, 5l, &zt, zrandomb); zlshift(zt, 1l, &za); do i0 = rand(); while (i0 == 0); i = i0; do { /* compute r = 2 * i * t + 1 */ zsmul(za, i, &zb); zsadd(zb, 1l, &zr); i++; } while (!zprobprime(zr, 5l)); /* compute p0 = ((2 * s) ^ (r - 2) mod r) * s - 1 */ zlshift(zs, 2l, &za); zsadd(zr, - 2l, &zb); zexpmod(za, zb, zr, &zc); zmul(zc, zs, &za); zsadd(za, - 1l, &zp0); zlshift(zr, 1l, &zb); zmul(zb, zs, &za); do j0 = rand(); while (j0 == 0); j = j0; k = 0; do { /* compute p = p0 + 2 * j * r * s */ zsmul(za, j, &zb); zadd(zb, zp0, zp); j++, k++; printf("\b\b\b\b\b%4ld", k); } while (k < 1000 && !zprobprime(*zp, 5l)); zfree(&za); zfree(&zb); zfree(&zc); zfree(&zr); zfree(&zs); zfree(&zt); zfree(&zp0); if (k == 1000) return Gordon(bit_length, zp); return z2log(*zp); } int main(void) { long bit_length, i; verylong zp = 0; for (i = 100; i <= 180; i += 20) { bit_length = Gordon(i, &zp); printf(" %3ld %3ld ", i, bit_length); zwriteln(zp);

} zfree(&zp); return 0;

4.62
/* Author:

Algorithm Maurer's algorithm for generating provable primes maurer.c freelip (2,715)
Pate Williams (c) 1997

*/

Maurer's algorithm for generating provable primes. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al page 153. <math.h> <stdio.h> <stdlib.h> <time.h> "lip.h"

#include #include #include #include #include

long OddRandom(long bit_length) { long i, mask = 1, n; bit_length--; for (i = 1; i <= bit_length; i++) mask |= 1 << i; if (bit_length < 16) n = rand(); else n = (rand() << 16) | rand(); n |= 1 << bit_length; n &= mask; if ((n & 1) == 0) n++; return n; } void PROVABLE_PRIME(long k, verylong *zn) { double c, r, s; int success; long B, m, n, p, sqrtn; verylong zI = 0, zR = 0, za = 0, zb = 0, zc = 0; verylong zd = 0, zk = 0, zl = 0, zq = 0, zu = 0; srand(time(NULL)); zrstarts(time(NULL)); if (k <= 20) { do { n = OddRandom(k); sqrtn = sqrt(n); zpstart2(); do p = zpnext(); while (n % p != 0 && p < sqrtn); } while (p < sqrtn);

zintoz(n, zn); } else { c = 0.1; m = 20; B = c * k * k; if (k > 2 * m) do { s = rand() / (double) RAND_MAX; r = pow(2.0, s - 1.0); } while (k - r * k <= m); else r = 0.5; PROVABLE_PRIME(r * k + 1, &zq); zone(&za); zlshift(za, k - 1, &zk); zcopy(zq, &za); zlshift(za, 1l, &zl); zdiv(zk, zl, &zI, &za); zsadd(zI, 1l, &zl); zlshift(zI, 1l, &zu); success = 0; while (!success) { do zrandomb(zu, &zR); while (zcompare(zR, zl) < 0); zmul(zR, zq, &za); zlshift(za, 1l, &zb); zsadd(zb, 1l, zn); zcopy(zR, &za); zlshift(za, 1l, &zR); zpstart2(); p = zpnext(); while (zsmod(*zn, p) != 0 && p < B) p = zpnext(); if (p >= B) { zcopy(*zn, &zc); zsadd(zc, - 2l, &zb); do zrandomb(*zn, &za); while (zscompare(za, 2l) < 0 || zcompare(za, zb) > 0); zsadd(*zn, - 1l, &zc); zexpmod(za, zc, *zn, &zb); if (zscompare(zb, 1l) == 0) { zexpmod(za, zR, *zn, &zb); zcopy(zb, &zd); zsadd(zd, - 1l, &zb); zgcd(zb, *zn, &zd); success = zscompare(zd, 1l) == 0; } } } } zfree(&zI); zfree(&zR); zfree(&za); zfree(&zb); zfree(&zc); zfree(&zd); zfree(&zk);

zfree(&zl); zfree(&zq); zfree(&zu);

int main(void) { long k; verylong zn = 0; for (k = 10; k <= 55; k += 5) { PROVABLE_PRIME(k, &zn); printf("%ld %ld %ld ", k, z2log(zn), zprobprime(zn, 5)); zwriteln(zn); } zfree(&zn); return 0;

4.69
/* Author:

Algorithm Testing a polynomial for irreducibility genirred.c freelip (7,086)


Pate Williams (c) 1997

Program to generate a random irreducible polynomial contained in Zp p prime. See "Handbook of Applied Cryptography" pages 157 - 158. Also see "A Course in Computational Algebraic Number Theory" by Henri Cohen pages 37 and 127. */ #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <time.h> #include "lip.h" #define POLY_SIZE 8192l void zpoly_copy(long da, verylong *za, verylong *zb, long *db) { long i; *db = da; for (i = 0; i <= da; i++) zcopy(za[i], &zb[i]);

void zpoly_mul(long m, long n, verylong *za, verylong *zb, verylong *zc, long *p) { long i, j, k; verylong zd = 0, zai = 0, zbk = 0, zsum = 0, zterm = 0; *p = m + n; for (k = 0; k <= *p; k++) {

zzero(&zsum); for (i = 0; i <= k; i++) { j = k - i; if (i > m) zzero(&zai); else zcopy(za[i], &zai); if (j > n) zzero(&zbk); else zcopy(zb[j], &zbk); zmul(zai, zbk, &zterm); zcopy(zsum, &zd); zadd(zterm, zd, &zsum); } zcopy(zsum, &zc[k]); } zfree(&zd); zfree(&zai); zfree(&zbk); zfree(&zsum); zfree(&zterm); } void zpoly_div(long m, long n, verylong *zu, verylong *zv, verylong *zq, verylong *zr, long *p, long *s) { long j, jk, k, nk; verylong za = 0, zb = 0, zvn = 0; zcopy(zv[n], &zvn); for (j = 0; j <= m; j++) zcopy(zu[j], &zr[j]); if (m < n) { *p = 0, *s = m; zzero(&zq[0]); } else { *p = m - n, *s = n - 1; for (k = *p; k >= 0; k--) { nk = n + k; zsexp(zvn, k, &za); zmul(zr[nk], za, &zq[k]); for (j = nk - 1; j >= 0; j--) { jk = j - k; if (jk >= 0) { zmul(zvn, zr[j], &za); zmul(zr[nk], zv[jk], &zb); zsub(za, zb, &zr[j]); } else { zcopy(zr[j], &za); zmul(zvn, za, &zr[j]); } } } while (*p > 0 && zscompare(zq[*p], 0l) == 0) *p = *p - 1; while (*s > 0 && zscompare(zr[*s], 0l) == 0) *s = *s - 1; } zfree(&za); zfree(&zb);

zfree(&zvn);

void zpoly_mod(verylong zp, verylong *za, long *da) { long i; verylong zb = 0; for (i = 0; i <= *da; i++) { zmod(za[i], zp, &zb); zcopy(zb, &za[i]); } while (*da > 0 && zscompare(za[*da], 0l) == 0) *da = *da - 1; zfree(&zb); } void zpoly_pow(long degreeA, long degreem, verylong zn, verylong zp, verylong *zA, verylong *zm, verylong *zs, long *ds) { long dP, dq, dx = degreeA, i; verylong za = 0, zb = 0, zP[POLY_SIZE], zq[POLY_SIZE], zx[POLY_SIZE], zy[POLY_SIZE]; for (i = 0; i < POLY_SIZE; i++) zP[i] = zq[i] = zx[i] = zy[i] = 0; *ds = 0; zcopy(zn, &za); zone(&zs[0]); for (i = 0; i <= dx; i++) zcopy(zA[i], &zx[i]); while (zscompare(za, 0l) > 0) { if (zodd(za)) { /* s = (s * x) % m; */ zpoly_mul(*ds, dx, zs, zx, zP, &dP); zpoly_div(dP, degreem, zP, zm, zq, zs, &dq, ds); zpoly_mod(zp, zs, ds); } zcopy(za, &zb); zrshift(zb, 1l, &za); if (zscompare(za, 0l) > 0) { /* x = (x * x) % m; */ for (i = 0; i <= dx; i++) zcopy(zx[i], &zy[i]); zpoly_mul(dx, dx, zx, zy, zP, &dP); zpoly_div(dP, degreem, zP, zm, zq, zx, &dq, &dx); zpoly_mod(zp, zx, &dx); } } zfree(&za); zfree(&zb); for (i = 0; i < POLY_SIZE; i++) { zfree(&zP[i]); zfree(&zq[i]); zfree(&zx[i]); zfree(&zy[i]); } }

void zpoly_sub(long da, long db, verylong *za, verylong *zb, verylong *zc, long *dc) { long i; verylong zz = 0; zzero(&zz); if (da >= db) { for (i = 0; i <= db; i++) zsub(za[i], zb[i], &zc[i]); for (i = db + 1; i <= da; i++) zcopy(za[i], &zc[i]); *dc = da; } else { for (i = 0; i <= da; i++) zsub(za[i], zb[i], &zc[i]); for (i = da + 1; i <= db; i++) zsub(zz, zb[i], &zc[i]); *dc = db; } zfree(&zz);

void zpoly_gcd(long degreeA, long degreeB, verylong zp, verylong *zA, verylong *zB, verylong *za, long *da) { int nonzero = 0, zero; long db, dq, dr, i; verylong zc = 0; verylong zb[POLY_SIZE], zq[POLY_SIZE], zr[POLY_SIZE]; for (i = 0; i < POLY_SIZE; i++) zb[i] = zq[i] = zr[i] = 0; if (degreeA > degreeB) { *da = degreeA; db = degreeB; for (i = 0; i <= *da; i++) zcopy(zA[i], &za[i]); for (i = 0; i <= db; i++) zcopy(zB[i], &zb[i]); } else { *da = degreeB; db = degreeA; for (i = 0; i <= *da; i++) zcopy(zB[i], &za[i]); for (i = 0; i <= db; i++) zcopy(zA[i], &zb[i]); } for (i = 0; i <= db && !nonzero; i++) nonzero = zscompare(zb[i], 0l) != 0; while (nonzero) { zpoly_div(*da, db, za, zb, zq, zr, &dq, &dr); for (i = 0; i <= dr; i++) { zcopy(zr[i], &zc); zmod(zc, zp, &zr[i]); } zero = 1;

} zfree(&zc); for (i = 0; i < POLY_SIZE; i++) { zfree(&zb[i]); zfree(&zq[i]); zfree(&zr[i]); } }

for (i = dr; i >= 0 && zero; i--) { zero = zscompare(zr[i], 0l) == 0; if (zero && dr > 0) dr--; } for (i = 0; i <= db; i++) zcopy(zb[i], &za[i]); *da = db; for (i = 0; i <= dr; i++) zcopy(zr[i], &zb[i]); db = dr; nonzero = 0; for (i = 0; i <= db && !nonzero; i++) nonzero = zscompare(zb[i], 0l) != 0;

void zpoly_print(long da, verylong *za) { long i; for (i = da; i >= 0; i--) { zwrite(za[i]); printf(" "); } printf("\n");

void zpoly_ext_euclid(long dg, long dh, verylong zp, verylong *zg, verylong *zh, verylong *zs, verylong *zt, verylong *zd, long *ds, long *dt, long *dd) { long da, dq, dr, ds1 = 0, ds2 = 0, dt1 = 0, dt2 = 0, i; verylong za[POLY_SIZE], zb[POLY_SIZE]; verylong zq[POLY_SIZE], zr[POLY_SIZE]; verylong zs1[POLY_SIZE], zs2[POLY_SIZE]; verylong zt1[POLY_SIZE], zt2[POLY_SIZE]; if (dh == 0 && zscompare(zh[0], 0l) == 0) { zpoly_copy(dg, zg, zd, dd); *ds = *dt = 0; zone(&zs[0]); zzero(&zt[0]); } for (i = 0; i < POLY_SIZE; i++) { za[i] = zb[i] = zq[i] = zr[i] = 0; zs1[i] = zs2[i] = zt1[i] = zt2[i] = 0; } zone(&zs2[0]); zzero(&zs1[0]); zzero(&zt2[0]); zone(&zt1[0]); while (dh != 0 || zscompare(zh[0], 0l) != 0) {

} zpoly_copy(dg, zg, zd, dd); zpoly_copy(ds2, zs2, zs, ds); zpoly_copy(dt2, zt2, zt, dt); for (i = 0; i < POLY_SIZE; i++) { zfree(&za[i]); zfree(&zb[i]); zfree(&zq[i]); zfree(&zr[i]); zfree(&zs1[i]); zfree(&zs2[i]); zfree(&zt1[i]); zfree(&zt2[i]); }

zpoly_div(dg, dh, zg, zh, zq, zr, &dq, &dr); zpoly_mod(zp, zq, &dq); zpoly_mod(zp, zr, &dr); zpoly_mul(dq, ds1, zq, zs1, za, &da); zpoly_sub(ds2, da, zs2, za, zs, ds); zpoly_mul(dq, dt1, zq, zt1, za, &da); zpoly_sub(dt2, da, zt2, za, zt, dt); zpoly_mod(zp, zs, ds); zpoly_mod(zp, zt, dt); zpoly_copy(dh, zh, zg, &dg); zpoly_copy(dr, zr, zh, &dh); zpoly_copy(ds1, zs1, zs2, &ds2); zpoly_copy(*ds, zs, zs1, &ds1); zpoly_copy(dt1, zt1, zt2, &dt2); zpoly_copy(*dt, zt, zt1, &dt1); #ifdef DEBUG printf("q = "); zpoly_print(dq, zq); printf("r = "); zpoly_print(dr, zr); printf("s = "); zpoly_print(*ds, zs); printf("t = "); zpoly_print(*dt, zt); printf("g = "); zpoly_print(dg, zg); printf("h = "); zpoly_print(dh, zh); printf("s2 = "); zpoly_print(ds2, zs2); printf("s1 = "); zpoly_print(ds1, zs1); printf("t2 = "); zpoly_print(dt2, zt2); printf("t1 = "); zpoly_print(dt1, zt1); #endif

void Recurse(long degreeA, verylong zp, verylong *zA, verylong *zroot, long *rootSize) { long dd, degreeB, dq, dr, du = 1, i; verylong zD = 0, za = 0, zb = 0, zc = 0, ze = 0; verylong zn = 0; verylong zB[POLY_SIZE], zd[POLY_SIZE]; verylong zq[POLY_SIZE], zr[POLY_SIZE]; verylong zu[2]; for (i = 0; i < POLY_SIZE; i++) zB[i] = zd[i] = zq[i] = zr[i] = 0; zu[0] = zu[1] = 0; if (degreeA != 0) {

if (degreeA == 1) { if (zscompare(zA[1], 0l) != 0) { zinvmod(zA[1], zp, &za); zmul(zA[0], za, &zb); znegate(&zb); zmod(zb, zp, &zroot[*rootSize]); } *rootSize = *rootSize + 1; } else if (degreeA == 2) { zsq(zA[1], &za); zmul(zA[0], zA[2], &zb); zlshift(zb, 2l, &zc); zsub(za, zc, &zb); zmod(zb, zp, &zD); zsqrtmod(zD, zp, &ze); zlshift(zA[2], 1l, &za); zinvmod(za, zp, &zD); zsub(ze, zA[1], &za); zmulmod(za, zD, zp, &zroot[*rootSize]); *rootSize = *rootSize + 1; znegate(&zA[1]); znegate(&ze); zadd(zA[1], ze, &za); zmulmod(za, zD, zp, &zroot[*rootSize]); *rootSize = *rootSize + 1; } else { zsadd(zp, - 1l, &za); zrshift(za, 1l, &zn); do { zrandomb(zp, &za); zcopy(za, &zu[0]); zone(&zu[1]); zpoly_pow(du, degreeA, zn, zp, zu, zA, zd, &dd); zsadd(zd[0], - 1l, &za); zcopy(za, &zd[0]); zpoly_gcd(dd, degreeA, zp, zd, zA, zB, &degreeB); } while (degreeB == 0 || degreeB == degreeA); Recurse(degreeB, zp, zB, zroot, rootSize); zpoly_div(degreeA, degreeB, zA, zB, zq, zr, &dq, &dr); zpoly_mod(zp, zq, &dq); Recurse(dq, zp, zq, zroot, rootSize); } } zfree(&zD); zfree(&za); zfree(&zb); zfree(&zc); zfree(&ze); zfree(&zn); for (i = 0; i < POLY_SIZE; i++) { zfree(&zB[i]); zfree(&zd[i]); zfree(&zq[i]); zfree(&zr[i]); }

zfree(&zu[0]); zfree(&zu[1]); } long horner(long degreeP, long p, long x, verylong *zP) { long i, r; verylong za = 0, zr = 0; zcopy(zP[degreeP], &zr); for (i = degreeP - 1; i >= 0; i--) { zsmul(zr, x, &za); zadd(za, zP[i], &zr); } r = zsmod(zr, p); zfree(&za); zfree(&zr); return r; } void FindRootsModuloAPrime(long degreeP, verylong zp, verylong *zP, verylong *zroot, long *rootSize) { long degreeA, dy, i, j, p, r; verylong za = 0, zt = 0; verylong zA[POLY_SIZE], zx[POLY_SIZE], zy[POLY_SIZE]; for (i = 0; i < POLY_SIZE; i++) zA[i] = zx[i] = zy[i] = 0; *rootSize = 0; if (zscompare(zp, degreeP) <= 0) { p = ztoint(zp); for (i = 0; i < p; i++) { r = horner(degreeP, p, i, zP); if (r == 0) { zintoz(i, &zroot[*rootSize]); *rootSize = *rootSize + 1; } } } else { zzero(&zx[0]); zone(&zx[1]); zpoly_pow(1, degreeP, zp, zp, zx, zP, zy, &dy); zsadd(zy[1], - 1l, &za); zcopy(za, &zy[1]); zpoly_gcd(dy, degreeP, zp, zy, zP, zA, &degreeA); if (zscompare(zA[0], 0l) == 0) { zzero(&zroot[*rootSize]); *rootSize = *rootSize + 1; for (i = 0; i < degreeA; i++) zcopy(zA[i + 1], &zA[i]); degreeA--; } Recurse(degreeA, zp, zA, zroot, rootSize); /* sort the roots using selection sort */

} zfree(&zt); for (i = 0; i < POLY_SIZE; i++) { zfree(&zA[i]); zfree(&zx[i]); zfree(&zy[i]); } }

for (i = 0; i < *rootSize - 1; i++) { for (j = i + 1; j < *rootSize; j++) { if (zcompare(zroot[i], zroot[j]) > 0) { zcopy(zroot[i], &zt); zcopy(zroot[j], &zroot[i]); zcopy(zt, &zroot[j]); } } }

void generate(long m, verylong zp, verylong *zf) /* generates a random irreducible polynomial over Zp of degree m */ { long i, rootSize; verylong *zroot; zroot = calloc(m + 1, sizeof(verylong)); if (!zroot) { fprintf(stderr, "fatal error\ninsufficient memory\n"); exit(1); } zone(&zf[0]); do { for (i = 1; i < m; i++) zrandomb(zp, &zf[i]); zone(&zf[m]); FindRootsModuloAPrime(m, zp, zf, zroot, &rootSize); } while (rootSize); for (i = 0; i <= m; i++) zfree(&zroot[i]);

int main(void) { char answer[256]; int non, one; long i, j, m; verylong zf[POLY_SIZE], zp = 0; zrstarts(time(NULL)); for (i = 0; i < POLY_SIZE; i++) zf[i] = 0; do { printf("degree of polynomial: "); scanf("%d", &m); do { printf("prime: "); zread(&zp); } while (!zprobprime(zp, 5l)); generate(m, zp, zf); printf("a random irreducible polynomial of ");

printf("degree %ld over Z", m); zwrite(zp); printf(" is as follows:\n"); for (i = m; i >= 0; i--) { zwrite(zf[i]); printf(" "); } printf("\n"); for (i = m; i >= 0; i--) { if (zscompare(zf[i], 0l) != 0) { if (i != m) { non = 0; for (j = i - 1; !non && j >= 0; j--) non = zscompare(zf[j], 0l) != 0; if (non) printf(" + "); one = zscompare(zf[i], 1l) == 0; if (!one) zwrite(zf[i]); if (i == 0 && one) printf(" + 1"); } if (i == 0) printf("\n"); else if (i == 1) { if (one) printf("x"); else printf(" * x"); } else if (i == m) printf("x ^ %ld", i); else if (one) printf("x ^ %ld", i); else printf(" * x ^ %ld", i); } } printf("again (n or y)? "); scanf("%s", answer); } while (tolower(answer[0]) == 'y'); zfree(&zp); for (i = 0; i < POLY_SIZE; i++) zfree(&zf[i]); return 0; }

Chapter 05
5.37 5.40

Pseudorandom Bits and Sequences

Algorithm Micali-Schnorr pseudorandom bit generator micali.c freelip (4,698) Algorithm Blum-Blum-Shub pseudorandom bit generator blumblum.c freelip (3,815)

5.37
/*

Algorithm Micali-Schnorr pseudorandom bit generator micali.c freelip (4,698)


Pate Williams (c) 1997

Author:

*/

The following program implements and tests the Micali-Schnorr random bits generator. The test suite is according to FIPS 140-1. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al Section 5.4.4 pages 181 - 183 and 5.37 Algorithm page 186. <stdio.h> <stdlib.h> <time.h> "lip.h" BIT_STRING_LENGTH 20000l MONOBIT_LO 9654l MONOBIT_HI 10346l POKER_LO 1.03 POKER_HI 57.4

#include #include #include #include #define #define #define #define #define

void Micali_Schnorr_gen_key(long bit_length, verylong *ze, verylong *zn, verylong *zx0, long *k, long *r) /* generates the key and seed for the Micali-Schnorr pseudorandom bits generator */ { long length = bit_length / 2, N; verylong zd = 0, zp = 0, zq = 0, zs = 0, zt = 0; verylong zphi = 0; zrstarts(time(NULL)); zrandomprime(length, 5l, &zp, zrandomb); zrandomprime(length, 5l, &zq, zrandomb); zmul(zp, zq, zn); zsadd(zp, - 1l, &zs); zsadd(zq, - 1l, &zt); zmul(zs, zt, &zphi); N = z2log(*zn); zpstart(); do { zintoz(zpnext(), ze); zgcd(*ze, zphi, &zd); zsmul(*ze, 80l, &zs); } while (zscompare(zd, 1l) != 0 && zscompare(zs, N) > 0); *k = N * (1.0 - 2 / (double) ztoint(*ze)); *r = N - *k; zrandomprime(*r, 5l, zx0, zrandomb); zfree(&zd); zfree(&zp); zfree(&zq);

zfree(&zs); zfree(&zt); zfree(&zphi);

void Micali_Schnorr_next_bits(long k, long r, verylong ze, verylong zn, verylong *zx, verylong *zz) /* gets the next bits in the sequence */ { verylong zx0 = 0, zy = 0; zcopy(*zx, &zx0); zexpmod(zx0, ze, zn, &zy); zhighbits(zy, r, zx); zlowbits(zy, k, zz); zfree(&zx0); zfree(&zy); } int FIPS_140_1(char *bit_string) /* Statistical tests for randomness returns - 3 if bit_string fails monobit test, - 2 if it fails poker test, - 1 if it fails runs test, 0 if it fails the long run test 1 otherwise */ { float X3, sum = 0.0; long B[6]= {0}, G[6] = {0}, n[16] = {0}; long i, index, j, k, max_run = 0, n1 = 0; long interval_lo[6] = {2267, 1079, 502, 223, 90, 90}; long interval_hi[6] = {2733, 1421, 748, 402, 223, 223}; /* monobit test */ for (i = 0; i < BIT_STRING_LENGTH; i++) if (bit_string[i] == 1) n1++; /* poker test */ i = 0; k = BIT_STRING_LENGTH / 4; for (j = 0; j < k; j++) { index = 8 * bit_string[i + 3] + 4 * bit_string[i + 2] + 2 * bit_string[i + 1] + bit_string[i]; n[index]++; i += 4; } for (i = 0; i < 16; i++) sum += n[i] * n[i]; X3 = 16.0 * sum / k - k; /* runs test */ i = 0; while (i < BIT_STRING_LENGTH) { j = 0; while (i < BIT_STRING_LENGTH && bit_string[i] == 1) i++, j++; if (j <= 6) B[j - 1]++; else B[5]++; if (j > max_run) max_run = j; while (i < BIT_STRING_LENGTH && bit_string[i] == 0) i++; } i = 0; while (i < BIT_STRING_LENGTH) {

} /* print out results of the tests */ printf("monobit statistic: %ld\n", n1); printf("poker test statistic: %lf\n", X3); printf("# blocks\tgaps\n"); for (i = 0; i < 6; i++) printf("%ld %4ld\t\t%4ld\n", i + 1, B[i], G[i]); printf("long runs statistic: %ld\n", max_run); /* compute return value based on statistics */ if (n1 <= MONOBIT_LO || n1 >= MONOBIT_HI) return - 3; if (X3 <= POKER_LO || X3 >= POKER_HI) return - 2; for (i = 0; i < 6; i++) { if (B[i] < interval_lo[i] || B[i] > interval_hi[i]) return - 1; if (G[i] < interval_lo[i] || G[i] > interval_hi[i]) return - 1; } if (max_run >= 34) return 0; return 1; } int main(void) { char bit_string[BIT_STRING_LENGTH]; long i = 0, j, k, r; verylong ze = 0, zn = 0, zx = 0, zy = 0, zz = 0; /* fill the buffer to be tested */ Micali_Schnorr_gen_key(256l, &ze, &zn, &zx, &k, &r); printf("%ld %ld\n", k, r); zwriteln(zx); while (i < BIT_STRING_LENGTH) { Micali_Schnorr_next_bits(k, r, ze, zn, &zx, &zz); for (j = 0; j < k; j++) { zlowbits(zz, 1l, &zy); if (i < BIT_STRING_LENGTH) bit_string[i++] = (char) ztoint(zy); zrshift(zz, 1l, &zy); zcopy(zy, &zz); } } printf("value of FIPS_140_1 = %d\n", FIPS_140_1(bit_string)); zfree(&ze); zfree(&zn); zfree(&zx); zfree(&zy); zfree(&zz); return 0;

j = 0; while (i < BIT_STRING_LENGTH && bit_string[i] == 0) i++, j++; if (j <= 6) G[j - 1]++; else G[5]++; if (j > max_run) max_run = j; while (i < BIT_STRING_LENGTH && bit_string[i] == 1) i++;

5.40
/* Author:

Algorithm Blum-Blum-Shub pseudorandom bit generator blumblum.c freelip (3,815)


Pate Williams (c) 1997

*/

The following program implements and tests the Blum-Blum-Shub random bits generator. The test suite is according to FIPS 140-1. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al Section 5.4.4 pages 181 - 183 and 5.40 Algorithm page 186. <stdio.h> <stdlib.h> <time.h> "lip.h" BIT_STRING_LENGTH 20000l MONOBIT_LO 9654l MONOBIT_HI 10346l POKER_LO 1.03 POKER_HI 57.4

#include #include #include #include #define #define #define #define #define

void bbs_gen_key(long bit_length, verylong *zn, verylong *zx0) /* generates the key and seed for the Blum-Blum-Shub random bits generator */ { long length = bit_length / 2; verylong zp = 0, zq = 0, zs = 0; zrstarts(time(NULL)); zrandomprime(- length, 5l, &zp, zrandomb); zrandomprime(- length, 5l, &zq, zrandomb); zmul(zp, zq, zn); do zrandomb(*zn, &zs); while (zscompare(zs, 0l) == 0); zmulmod(zs, zs, *zn, zx0); zfree(&zp); zfree(&zq); zfree(&zs); } long bbs_next_bits(long number, verylong zn, verylong *zx) /* gets number low order bits of x * x mod n */ { long low_bits; verylong zx0 = 0; zcopy(*zx, &zx0); zmulmod(zx0, zx0, zn, zx); zlowbits(*zx, number, &zx0); low_bits = zx0[1]; zfree(&zx0); return low_bits; }

int FIPS_140_1(char *bit_string) /* Statistical tests for randomness returns - 3 if bit_string fails monobit test, - 2 if it fails poker test, - 1 if it fails runs test, 0 if it fails the long run test 1 otherwise */ { float X3, sum = 0.0; long B[6]= {0}, G[6] = {0}, n[16] = {0}; long i, index, j, k, max_run = 0, n1 = 0; long interval_lo[6] = {2267, 1079, 502, 223, 90, 90}; long interval_hi[6] = {2733, 1421, 748, 402, 223, 223}; /* monobit test */ for (i = 0; i < BIT_STRING_LENGTH; i++) if (bit_string[i] == 1) n1++; /* poker test */ i = 0; k = BIT_STRING_LENGTH / 4; for (j = 0; j < k; j++) { index = 8 * bit_string[i + 3] + 4 * bit_string[i + 2] + 2 * bit_string[i + 1] + bit_string[i]; n[index]++; i += 4; } for (i = 0; i < 16; i++) sum += n[i] * n[i]; X3 = 16.0 * sum / k - k; /* runs test */ i = 0; while (i < BIT_STRING_LENGTH) { j = 0; while (i < BIT_STRING_LENGTH && bit_string[i] == 1) i++, j++; if (j <= 6) B[j - 1]++; else B[5]++; if (j > max_run) max_run = j; while (i < BIT_STRING_LENGTH && bit_string[i] == 0) i++; i = 0; while (i < BIT_STRING_LENGTH) { j = 0; while (i < BIT_STRING_LENGTH && bit_string[i] == 0) if (j <= 6) G[j - 1]++; else G[5]++; if (j > max_run) max_run = j; while (i < BIT_STRING_LENGTH && bit_string[i] == 1) } /* print out results of the tests */ printf("monobit statistic: %ld\n", n1); printf("poker test statistic: %lf\n", X3); printf("# blocks\tgaps\n"); for (i = 0; i < 6; i++) printf("%ld %4ld\t\t%4ld\n", i + 1, B[i], G[i]); printf("long runs statistic: %ld\n", max_run); /* compute return value based on statistics */ if (n1 <= MONOBIT_LO || n1 >= MONOBIT_HI) return - 3; if (X3 <= POKER_LO || X3 >= POKER_HI) return - 2; for (i = 0; i < 6; i++) { if (B[i] < interval_lo[i] || B[i] > interval_hi[i]) if (G[i] < interval_lo[i] || G[i] > interval_hi[i])

i++, j++; i++;

return - 1; return - 1;

} if (max_run >= 34) return 0; return 1;

int main(void) { char bit_string[BIT_STRING_LENGTH]; long i; verylong zn = 0, zx0 = 0; /* fill the buffer to be tested */ bbs_gen_key(256l, &zn, &zx0); for (i = 0; i < BIT_STRING_LENGTH; i++) bit_string[i] = (char) bbs_next_bits(1l, zn, &zx0); printf("value of FIPS_140_1 = %d\n", FIPS_140_1(bit_string)); zfree(&zn); zfree(&zx0); return 0;

Chapter 06
6.30 6.68

Stream Ciphers

Algorithm Berlekamp-Massey Algorithm massey (2,012) Algorithm Keystream generator for SEAL 2.0

order information If you are a citizen of the United States and are currently residing in the United States with an e-mail address that is verifiably in the United States, then e-mail me to get a copy of SEAL 2.0 pate@mindspring.com Please specify the algorithm(s) and MIME or UUencoded format for the return e-mail attachment. You must confirm in writing that are a citizen of the U.S. and currently residing in the U.S. Don't forget to include your e-mail address. 6.30
/* Author: Pate Williams (c) 1997 The following code tests an implementation of the Berlekamp-Massey algorithm for finding the

Algorithm Berlekamp-Massey Algorithm massey (2,012)

*/

linear complexity of a finite binary sequence. This is useful in analyzing linear feedback shift registers (LFSRs). See "Handbook of Applied Cryptography" by Alfred J. Menezes et al 6.30 Algorithm page 201.

#include <stdio.h> #include <stdlib.h> long BerlekampMassey(char *s, long n, long *C) /* returns the linear complexity of the finite binary sequence s of length n */ { long L = 0, N = 0, d, e, i, m = - 1, n1 = n + 1, sum; long dB = 0, dC = 0, dT; long *B = malloc(n1 * sizeof(long)); long *D = malloc(n1 * sizeof(long)); long *T = malloc(n1 * sizeof(long)); for (i = 1; i < n1; i++) B[i] = C[i] = T[i] = 0; T[0] = 0; C[0] = B[0] = 1; while (N < n) { sum = 0; for (i = 1; i <= L; i++) sum += C[i] * s[N - i]; d = (s[N] + sum) & 1l; if (d == 1) { dT = dC; for (i = 0; i <= dT; i++) T[i] = C[i]; e = N - m; for (i = 0; i < e; i++) D[i] = 0; for (i = 0; i <= dB; i++) D[i + e] = B[i]; D[e] = 1; for (i = 0; i <= dB + e; i++) C[i] = (C[i] + D[i]) & 1l; if (dB + e > dC) dC = dB + e; if (L <= N / 2) { dB = dT; for (i = 0; i <= dB; i++) B[i] = T[i]; L = N + 1 - L, m = N; } } printf("s = %ld d = %ld T = ", s[N], d); for (i = 0; i <= L; i++) printf("%ld ", T[i]); printf("C = "); for (i = 0; i <= L; i++) printf("%ld ", C[i]); printf("L = %ld m = %ld B = ", L, m); for (i = 0; i <= L; i++) printf("%ld ", B[i]); printf("%ld\n", N); N++; } free(B); free(D); free(T); return L; }

void main(void) { char s[9] = {0, 0, 1, 1, 0, 1, 1, 1, 0}; long C[10], i, n = 9, L = BerlekampMassey(s, n, C); printf("linear complexity: %ld\n", L); printf("polynomial: "); for (i = 0; i <= L; i++) printf("%ld ", C[i]);

6.68 Algorithm Keystream generator for SEAL 2.0

Chapter 07
7.82 7.94 7.101 7.108 7.115

Block Ciphers

Algorithm Data Encryption Standard (DES) des (11,555) Algorithm Fast Data Encipherment Algorithm (FEAL-8) feal_8 (3,827) Algorithm IDEA encryption idea (6,009) Algorithm SAFER K-64 encryption (r rounds) saferk64 (6,526) Algorithm RC5 encryption (w-bit wordsize, r rounds, b-byte key) rc5 (2,468)

order information If you are a citizen of the United States and are currently residing in the United States with an e-mail address that is verifiably in the United States, then e-mail me to get copies of DES, FEAL-8, IDEA, SAFER K64, and/or RC5 pate@mindspring.com Please specify the algorithm(s) and MIME or UUencoded format for the return e-mail attachment. You must confirm in writing that are a citizen of the U.S. and currently residing in the U.S. Don't forget to include your e-mail address.

7.82 7.94

Algorithm Data Encryption Standard (DES) des (11,555) Algorithm Fast Data Encipherment Algorithm (FEAL-8) feal_8 (3,827) Algorithm IDEA encryption idea (6,009) Algorithm SAFER K-64 encryption (r rounds) saferk64 (6,526) Algorithm RC5 encryption (w-bit wordsize, r rounds, b-byte key) rc5 (2,468)

7.101 7.108 7.115

Chapter 08
8.3 8.11 8.18 8.37 8.51 8.56

Public-Key Encryption

Algorithm RSA public-key encryption rsa freelip (7,169) Algorithm Rabin public-key encryption rab freelip (10,082) Algorithm ElGamal public-key encryption elgamal freelip (8,872) Algorithm Basic Merkle-Hellman knapsack public-key encryption mh freelip (3,526) Algorithm Goldwasser-Micali probabilistic public-key encryption goldmica freelip (3,021) Algorithm Blum-Goldwasser probabilistic public-key encryption blumgold freelip (4,559)

order information If you are a citizen of the United States and are currently residing in the United States with an e-mail address that is verifiably in the United States, then e-mail me to get copies of RSA, Rabin, ElGamal, MerkleHellman, Goldwasser-Micali, and/or Blum-Goldwasser public-key encryption pate@mindspring.com Please specify the algorithm(s) and MIME or UUencoded format for the return e-mail attachment. You must confirm in writing that are a citizen of the U.S. and currently residing in the U.S. Don't forget to include your e-mail address. 8.3 8.11 8.18 8.37 Algorithm RSA public-key encryption rsa freelip (7,169) Algorithm Rabin public-key encryption rab freelip (10,082) Algorithm ElGamal public-key encryption elgamal freelip (8,872) Algorithm Basic Merkle-Hellman knapsack public-key encryption mh freelip (3,526) Algorithm Goldwasser-Micali probabilistic public-key encryption goldmica freelip (3,021) Algorithm Blum-Goldwasser probabilistic public-key encryption blumgold freelip (4,559)

8.51

8.56

Chapter 09
9.41 9.46 9.47 9.53

Hash Functions and Data Integrity

Algorithm Matyas-Meyer-Oseas hash (DES-based) mmohash (11,633) Algorithm MDC-2 (DES-based) mdc_2 (12,115) Algorithm MDC-4 (DES-based) mdc_3 (12,504) Algorithm Secure Hash Algorithm - revised (SHA-1) sha1 (3,987)

order information If you are a citizen of the United States and are currently residing in the United States with an e-mail address that is verifiably in the United States, then e-mail me to get a copy of Matyas-Meyer-Oseas hash, MDC_2 (DES-based), MDC_4 (DES-based), and/or SHA-1 pate@mindspring.com Please specify the algorithm(s) and MIME or UUencoded format for the return e-mail attachment. You must confirm in writing that are a citizen of the U.S. and currently residing in the U.S. Don't forget to include your e-mail address. 9.41 Algorithm Matyas-Meyer-Oseas hash (DES-based) mmohash (11,633) Algorithm MDC-2 (DES-based) mdc_2 (12,115) Algorithm MDC-4 (DES-based) mdc_3 (12,504) Algorithm Secure Hash Algorithm - revised (SHA-1) sha1 (3,987)

9.46 9.47 9.53

Chapter 11

Digital Sigantures

11.30 11.40 11.48 11.56

Algorithm Modified-Rabin public-key signature generation and verification rabin freelip (3,683) Algorithm Feige-Fiat-Shamir signature generation and verification ffs freelip (7,654) Algorithm GQ signature generation and verification gq freelip (10,079) Algorithm DSA signature generation and verification dsa (9,680)

11.102 Algorithm GMR one-time signature generation and verification gmr freelip (2,816) 11.113 Algorithm ESIGN signature generation and verification esign freelip (7,507)
order information

If you are a citizen of the United States and are currently residing in the United States with an e-mail address that is verifiably in the United States, then e-mail me to get copies of modified-Rabin, Feige-FiatShamir, GQ, DSA, GMR and/or ESIGN signature scheme pate@mindspring.com Please specify the algorithm(s) and MIME or UUencoded format for the return e-mail attachment. You must confirm in writing that are a citizen of the U.S. and currently residing in the U.S. Don't forget to include your e-mail address. 11.30 11.40 11.48 11.56 Algorithm Modified-Rabin public-key signature generation and verification rabin freelip (3,683) Algorithm Feige-Fiat-Shamir signature generation and verification ffs freelip (7,654) Algorithm GQ signature generation and verification gq freelip (10,079) Algorithm DSA signature generation and verification dsa (9,680)

11.102 Algorithm GMR one-time signature generation and verification gmr freelip (2,816) 11.113 Algorithm ESIGN signature generation and verification esign freelip (7,507)

Chapter 14
14.2

Efficient Implementation

Algorithm Multiple-precision addition mpadd.c (2,068)

14.9 14.12 14.16 14.20 14.32 14.36 14.42 14.54 14.61 14.71 14.82 14.83 14.85 14.94 14.98

Algorithm Multiple-precision subtraction mpsub.c (3,710) Algorithm Multiple-precision multiplication mpmul.c (3,178) Algotithm Multiple-precision squaring mpsqr.c (2,813) Algorithm Multiple-precision division mpdiv.c (11,702) Algorithm Montgomery reduction monty.c freelip (1,947) Algorithm Montgomery multiplication montmult.c freelip (2,333) Algorithm Barrett modular reduction barrett.c freelip (2,732) Algorithm Binary gcd algorithm bingcd.c (904) Algorithm Binary extended gcd algorithm binegcd.c freelip (2,808) Algorithm Garner's algorithm for CRT garner.c freelip (5,059) Algorithm Left-to-right k-ary exponentiation ltrkary.c freelip (1,482) Algorithm Modified left-to-right k-ary exponentiation mltrkary.c freelip (2,441) Algorithm Sliding window exponentiation swindow.c freelip (2,190) Algorithm Montgomery exponentiation montexpo.c freelip (3,032) Algorithm Addition chain exponentiation addchain.c freelip (1,650)

14.117 Algorithm Fixed-base comb method for exponentiation fbcomb.c freelip (3,660) 14.121 Algorithm Signed-digit recoding sdrec.c freelip (960) 14.130 Algorithm Exponentiation using an SR(k) representation srk.c freelip (2,505)

14.2
/* Author:

Algorithm Multiple-precision addition mpadd.c (2,068)


Pate Williams (c) 1997

Multiple-precision addition. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al 14.2.2 Section pages 594 - 595. */ #include <stdio.h> #include <stdlib.h> #define BASE 10 typedef long * mp; void mp_free(mp *mpa) { free(*mpa); *mpa = 0; } void mp_set_length(long length, mp *mpa) { mp mpx = *mpa; if (mpx != 0 && length <= mpx[0]) return; if (mpx != 0) free(mpx); mpx = calloc(length + 1, sizeof(long)); mpx[0] = length; *mpa = mpx; } void mp_add(mp mpx, mp mpy, mp *mpw) { long c = 0, i, s, x_len = mpx[0], y_len = mpy[0]; long mx = max(x_len, y_len); long mn = min(x_len, y_len); long w_len = mx + 1; mp_set_length(w_len, mpw); for (i = 1; i <= mn; i++) { s = mpx[i] + mpy[i] + c; (*mpw)[i] = s % BASE; c = s < BASE ? 0 : 1; } if (x_len > y_len) { for (i = mn + 1; i <= x_len; i++) { s = mpx[i] + c; (*mpw)[i] = s % BASE; c = s < BASE ? 0 : 1; } } else if (x_len < y_len) {

} (*mpw)[w_len] = c;

for (i = mn + 1; i <= y_len; i++) { s = mpy[i] + c; (*mpw)[i] = s % BASE; c = s < BASE ? 0 : 1; }

void mp_dump(mp mpa) { long i; for (i = mpa[0]; i >= 1; i--) printf("%ld", mpa[i]); printf("\n"); } void main(void) { mp mpw = 0, mpx = 0, mpy = 0; mp_set_length(2, &mpx); mp_set_length(3, &mpy); mpx[1] = 9, mpx[2] = 9; mpy[1] = 1, mpy[2] = 0, mp_add(mpx, mpy, &mpw); mp_dump(mpx); mp_dump(mpy); mp_dump(mpw); mp_set_length(3, &mpx); mp_set_length(2, &mpy); mpx[1] = 1, mpx[2] = 2, mpy[1] = 9, mpy[2] = 8; mp_add(mpx, mpy, &mpw); mp_dump(mpx); mp_dump(mpy); mp_dump(mpw); mp_set_length(3, &mpx); mp_set_length(3, &mpy); mpx[1] = 1, mpx[2] = 2, mpy[1] = 4, mpy[2] = 5; mp_add(mpx, mpy, &mpw); mp_dump(mpx); mp_dump(mpy); mp_dump(mpw); mp_free(&mpw); mp_free(&mpx); mp_free(&mpy);

mpy[3] = 1;

mpx[3] = 3;

mpx[3] = 3; mpy[3] = 7;

14.9
/* Author:

Algorithm Multiple-precision subtraction mpsub.c (3,710)


Pate Williams (c) 1997

Multiple-precision subtraction. See "Handbook

of Applied Cryptography" by Alfred J. Menezes et al 14.2.2 Section pages 594 - 595. */ #include #include #include #include <assert.h> <mem.h> <stdio.h> <stdlib.h>

#define BASE 10 typedef long * mp; void mp_set_length(long length, mp *mpa) { mp mpx = *mpa; if (mpx != 0) free(mpx); mpx = calloc(length + 2, sizeof(long)); assert(mpx != 0); mpx[0] = length; *mpa = mpx; } void mp_extend(long length, mp mpa, mp *mpb) { long i, len = mpa[0], sign = mpa[len + 1]; mp mpx; mp_set_length(length, mpb); mpx = *mpb; memcpy(mpx, mpa, (len + 2) * sizeof(long)); if (length == len) return; for (i = len + 1; i <= length; i++) mpx[i] = sign; mpx[0] = length; mpx[length + 1] = sign;

void mp_free(mp *mpa) { free(*mpa); *mpa = 0; } void mp_copy(mp mpa, mp *mpb) { long length = mpa[0]; mp_set_length(length, mpb); memcpy(*mpb, mpa, (length + 2) * sizeof(long));

void mp_negate(mp *mpa) { mp mpx = *mpa; long base_1 = BASE - 1, c = 1, i, length = mpx[0] + 1, s;

long sign = mpx[length]; for (i = 1; i <= length; i++) mpx[i] = base_1 - mpx[i]; for (i = 1; i <= length; i++) { s = mpx[i] + c; mpx[i] = s % BASE; c = s < BASE ? 0 : 1; } mpx[length] = (sign == 0) ? base_1 : 0; } void mp_dump(mp mpa) { char sign = '+'; long i; mp mpb = 0; mp_copy(mpa, &mpb); if (mpb[mpa[0] + 1] != 0) { mp_negate(&mpb); sign = '-'; } printf("%c", sign); for (i = mpb[0]; i >= 1; i--) printf("%ld", mpb[i]); printf("\n");

void mp_add(mp mpx, mp mpy, mp *mpw) /* calcuates w = x + y */ { long c = 0, i, s, x_len = mpx[0], y_len = mpy[0]; long length, mx = max(x_len, y_len); long w_len = mx; mp mpa = 0, mpb = 0, mpv; if (x_len == y_len) w_len++; mp_extend(mx, mpx, &mpa); mp_extend(mx, mpy, &mpb); #ifdef DEBUG for (i = mpa[0] + 1; i >= 1; i--) printf("%ld", mpa[i]); printf("\n"); for (i = mpb[0] + 1; i >= 1; i--) printf("%ld", mpb[i]); printf("\n"); #endif mp_set_length(w_len, mpw); mpv = *mpw; for (i = 1; i <= mx + 1; i++) { s = mpa[i] + mpb[i] + c; mpv[i] = s % BASE; c = s < BASE ? 0 : 1; } length = mpv[0]; for (i = length; i >= 1 && mpv[i] == 0; i--) mpv[0]--;

mpv[mpv[0] + 1] = mpv[length + 1]; mp_free(&mpa); mp_free(&mpb);

void mp_sub(mp mpx, mp mpy, mp *mpw) /* calculates w = x - y */ { mp mpz = 0; mp_copy(mpy, &mpz); mp_negate(&mpz); mp_add(mpx, mpz, mpw); mp_free(&mpz); } void main(void) { mp mpw = 0, mpx = 0, mpy = 0; mp_set_length(2, &mpx); mp_set_length(3, &mpy); mpx[1] = 9, mpx[2] = 9, mpy[1] = 1, mpy[2] = 0, mp_sub(mpx, mpy, &mpw); mp_dump(mpx); mp_dump(mpy); mp_dump(mpw); mp_set_length(3, &mpx); mp_set_length(2, &mpy); mpx[1] = 1, mpx[2] = 2, mpy[1] = 9, mpy[2] = 8, mp_sub(mpx, mpy, &mpw); mp_dump(mpx); mp_dump(mpy); mp_dump(mpw); mp_set_length(3, &mpx); mp_set_length(3, &mpy); mpx[1] = 1, mpx[2] = 2, mpy[1] = 4, mpy[2] = 5; mp_sub(mpx, mpy, &mpw); mp_dump(mpx); mp_dump(mpy); mp_dump(mpw); mp_set_length(3, &mpx); mp_set_length(3, &mpy); mpx[1] = 2, mpx[2] = 8, mpy[1] = 4, mpy[2] = 5; mp_add(mpx, mpy, &mpw); mp_dump(mpx); mp_dump(mpy); mp_dump(mpw); mp_free(&mpw); mp_free(&mpx); mp_free(&mpy);

mpx[3] = 0; mpy[3] = 1, mpy[4] = 0;

mpx[3] = 3, mpx[4] = 0; mpy[3] = 0;

mpx[3] = 3, mpx[4] = 0; mpy[3] = 2, mpy[4] = 0;

mpx[3] = 8, mpx[4] = 0; mpy[3] = 2, mpy[4] = 0;

14.12
/* Author:

Algorithm Multiple-precision multiplication mpmul.c (3,178)


Pate Williams (c) 1997

Multiple-precision multiplication. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al 14.2.3 Section pages 595 - 596. */ #include #include #include #include <assert.h> <mem.h> <stdio.h> <stdlib.h>

#define BASE 10 #define DEBUG typedef long * mp; void mp_set_length(long length, mp *mpa) { mp mpx = *mpa; if (mpx != 0) free(mpx); mpx = calloc(length + 2, sizeof(long)); assert(mpx != 0); mpx[0] = length; *mpa = mpx;

void mp_free(mp *mpa) { free(*mpa); *mpa = 0; } void mp_copy(mp mpa, mp *mpb) { long length = mpa[0]; mp_set_length(length, mpb); memcpy(*mpb, mpa, (length + 2) * sizeof(long));

void mp_negate(mp *mpa) { mp mpx = *mpa; long base_1 = BASE - 1, c = 1, i, length = mpx[0] + 1, s; long sign = mpx[length]; for (i = 1; i <= length; i++) mpx[i] = base_1 - mpx[i]; for (i = 1; i <= length; i++) { s = mpx[i] + c; mpx[i] = s % BASE; c = s < BASE ? 0 : 1;

} mpx[length] = (sign == 0) ? base_1 : 0; } void mp_dump(mp mpa) { char sign = '+'; long i; mp mpb = 0; mp_copy(mpa, &mpb); if (mpb[mpa[0] + 1] != 0) { mp_negate(&mpb); sign = '-'; } printf("%c", sign); for (i = mpb[0]; i >= 1; i--) printf("%ld", mpb[i]); printf("\n");

void mp_mul(mp mpx, mp mpy, mp *mpw) /* calcuates w = x * y */ { long c, i, ij, j, x_len = mpx[0], y_len = mpy[0]; long u, uv, v, w_len = x_len + y_len + 2, w_sign; long x_sign = mpx[x_len + 1], y_sign = mpy[y_len + 1]; mp mpa = 0, mpb = 0, mpv; mp_copy(mpx, &mpa); mp_copy(mpy, &mpb); if (x_sign != 0) mp_negate(&mpa); if (y_sign != 0) mp_negate(&mpb); w_sign = (x_sign == y_sign) ? 0 : BASE - 1; mp_set_length(w_len, mpw); mpv = *mpw; #ifdef DEBUG printf("i j c u v w\n"); #endif for (i = 1; i <= y_len; i++) { c = 0; for (j = 1; j <= x_len; j++) { ij = i + j - 1; uv = mpv[ij] + mpa[j] * mpb[i] + c; u = uv / BASE; v = uv % BASE; mpv[ij] = v; c = u; #ifdef DEBUG { long k; printf("%ld %ld %ld %ld %ld ", i, j, c, u, v); for (k = w_len; k >= 1; k--) printf("%ld ", mpv[k]); printf("\n"); }

} for (i = w_len; i >= 1 && mpv[i] == 0; i--) mpv[0]--; if (w_sign != 0) mp_negate(mpw); mp_free(&mpa); mp_free(&mpb); } int main(void) { mp mpw = 0, mpx = 0, mpy = 0; mp_set_length(4, &mpx); mp_set_length(3, &mpy); mpx[1] = 4, mpx[2] = 7, mpx[3] = 2, mpx[4] = 9; mpy[1] = 7, mpy[2] = 4, mpy[3] = 8; mp_mul(mpx, mpy, &mpw); mp_dump(mpx); mp_dump(mpy); mp_dump(mpw); mp_negate(&mpx); mp_mul(mpx, mpy, &mpw); mp_dump(mpx); mp_dump(mpy); mp_dump(mpw); mp_negate(&mpx); mp_negate(&mpy); mp_mul(mpx, mpy, &mpw); mp_dump(mpx); mp_dump(mpy); mp_dump(mpw); mp_negate(&mpx); mp_mul(mpx, mpy, &mpw); mp_dump(mpx); mp_dump(mpy); mp_dump(mpw); mp_free(&mpw); mp_free(&mpx); mp_free(&mpy); return 0; }

#endif } mpv[i + x_len] = u;

14.16
/* Author:

Algotithm Multiple-precision squaring mpsqr.c (2,813)


Pate Williams (c) 1997

Multiple-precision squaring. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al 14.2.4 Section pages 596 - 597. */ #include <assert.h> #include <mem.h>

#include <stdio.h> #include <stdlib.h> #define BASE 10 #define DEBUG typedef long * mp; void mp_set_length(long length, mp *mpa) { mp mpx = *mpa; if (mpx != 0) free(mpx); mpx = calloc(length + 2, sizeof(long)); assert(mpx != 0); mpx[0] = length; *mpa = mpx;

void mp_free(mp *mpa) { free(*mpa); *mpa = 0; } void mp_copy(mp mpa, mp *mpb) { long length = mpa[0]; mp_set_length(length, mpb); memcpy(*mpb, mpa, (length + 2) * sizeof(long));

void mp_negate(mp *mpa) { mp mpx = *mpa; long base_1 = BASE - 1, c = 1, i, length = mpx[0] + 1, s; long sign = mpx[length]; for (i = 1; i <= length; i++) mpx[i] = base_1 - mpx[i]; for (i = 1; i <= length; i++) { s = mpx[i] + c; mpx[i] = s % BASE; c = s < BASE ? 0 : 1; } mpx[length] = (sign == 0) ? base_1 : 0;

void mp_dump(mp mpa) { char sign = '+'; long i; mp mpb = 0; mp_copy(mpa, &mpb); if (mpb[mpa[0] + 1] != 0) {

mp_negate(&mpb); sign = '-'; } printf("%c", sign); for (i = mpb[0]; i >= 1; i--) printf("%ld", mpb[i]); printf("\n");

void mp_sqr(mp mpx, mp *mpw) /* calcuates w = x * x */ { long c, i, ij, j, x_len = mpx[0]; long u, uv, v, w_len = 2 * x_len; long x_sign = mpx[x_len + 1]; mp mpa = 0, mpv; mp_copy(mpx, &mpa); if (x_sign != 0) mp_negate(&mpa); mp_set_length(w_len, mpw); mpv = *mpw; #ifdef DEBUG printf("i j u v w\n"); #endif for (i = 1; i <= x_len; i++) { ij = 2 * i - 1; u = mpa[i]; uv = mpv[ij] + u * u; u = uv / BASE; v = uv % BASE; mpv[ij] = v; c = u; for (j = i + 1; j <= x_len; j++) { ij = i + j - 1; uv = mpv[ij] + 2 * mpa[j] * mpa[i] + c; u = uv / BASE; v = uv % BASE; mpv[ij] = v; c = u; #ifdef DEBUG { long k; printf("%ld %ld %2ld %ld ", i, j, u, v); for (k = w_len; k >= 1; k--) printf("%2ld ", mpv[k]); printf("\n");

} #ifdef DEBUG { long k;

} mpv[i + x_len] = u;

} #endif

printf("- - %2ld %ld ", u, v);

} #endif mp_free(&mpa); }

for (k = w_len; k >= 1; k--) printf("%2ld ", mpv[k]); printf("\n");

int main(void) { mp mpw = 0, mpx = 0; mp_set_length(3, &mpx); mpx[1] = 9, mpx[2] = 8, mpx[3] = 9; mp_sqr(mpx, &mpw); mp_dump(mpx); mp_dump(mpw); mp_negate(&mpx); mp_sqr(mpx, &mpw); mp_dump(mpx); mp_dump(mpw); mp_free(&mpw); mp_free(&mpx); return 0; }

14.20
/* Author:

Algorithm Multiple-precision division mpdiv.c (11,702)


Pate Williams (c) 1997

Multiple-precision division. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al 14.2.5 Section pages 598 - 599. */ #include #include #include #include #include #define #define #define #define <assert.h> <mem.h> <stdio.h> <stdlib.h> <string.h> BASE 10l BITS_PER_LONG 32l DIGITS_PER_LINE 78l DEBUG

typedef long * mp; void mp_set_length(long length, mp *mpa) { mp mpx = *mpa; if (mpx) { if (length > mpx[0]) { mpx = realloc(mpx, (length + 2) * sizeof(long)); assert(mpx != 0);

} memset(mpx, 0, (length + 2) * sizeof(long)); } else { mpx = calloc(length + 2, sizeof(long)); assert(mpx != 0); } mpx[0] = length; *mpa = mpx;

void mp_copy(mp mpa, mp *mpb) { long length = mpa[0]; mp_set_length(length, mpb); memcpy(*mpb, mpa, (length + 2) * sizeof(long));

void mp_extend(long length, mp mpa, mp *mpb) { long i, len = mpa[0], sign = mpa[len + 1]; mp mpx; mp_set_length(length, mpb); mpx = *mpb; memcpy(mpx, mpa, (len + 2) * sizeof(long)); if (length == len) return; for (i = len + 1; i <= length; i++) mpx[i] = sign; mpx[0] = length; mpx[length + 1] = sign; } void mp_free(mp *mpa) { free(*mpa); *mpa = 0; } void mp_add(mp mpx, mp mpy, mp *mpw) /* calcuates w = x + y */ { long c = 0, i, s, x_len = mpx[0], y_len = mpy[0]; long mx = max(x_len, y_len); long w_len = mx; mp mpa = 0, mpb = 0, mpv; if (x_len == y_len) w_len++; mp_extend(w_len, mpx, &mpa); mp_extend(w_len, mpy, &mpb); mp_set_length(w_len, mpw); mpv = *mpw; for (i = 1; i <= w_len + 1; i++) { s = mpa[i] + mpb[i] + c; mpv[i] = s % BASE; c = s < BASE ? 0 : 1;

} mp_free(&mpa); mp_free(&mpb);

void mp_negate(mp *mpa) { mp mpx = *mpa; long base_1 = BASE - 1, c = 1, i, length = mpx[0] + 1, s; for (i = 1; i <= length; i++) mpx[i] = base_1 - mpx[i]; for (i = 1; i <= length; i++) { s = mpx[i] + c; mpx[i] = s % BASE; c = s < BASE ? 0 : 1; }

int mp_compares(mp mpa, long s) { int value; long a_len = mpa[0], s_sign = s < 0; long a_sign = mpa[a_len + 1] != 0; mp mpb = 0; if (a_sign != s_sign) value = a_sign ? - 1 : + 1; else if (a_len > 1) value = s_sign ? - 1 : + 1; else { if (s_sign) s = - s; mp_copy(mpa, &mpb); if (a_sign) mp_negate(&mpb); if (mpb[1] == 0) value = 0; else value = mpb[1] - s; if (a_sign) value = - value; } return value;

void mp_dump(mp mpa) { char sign = '+'; long i; mp mpb = 0; mp_copy(mpa, &mpb); if (mpb[mpa[0] + 1] != 0) { mp_negate(&mpb); sign = '-'; } printf("%c", sign); for (i = mpb[0]; i >= 1; i--) printf("%ld", mpb[i]); printf("\n"); }

void mp_sub(mp mpx, mp mpy, mp *mpw) /* calculates w = x - y */ { mp mpz = 0; mp_copy(mpy, &mpz); mp_negate(&mpz); mp_add(mpx, mpz, mpw); mp_free(&mpz); } int mp_compare(mp mpx, mp mpy) { int zero; long i, length, sign; mp mpz = 0; mp_sub(mpx, mpy, &mpz); length = mpz[0]; sign = mpz[length + 1]; if (sign != 0) return - 1; for (zero = 1, i = length; i >= 1 && zero; i--) zero = mpz[i] == 0; if (zero) return 0; return + 1; } void mp_adds(mp mpx, long y, mp *mpw) /* calcuates w = x + y */ { int zero; long c = y, i, s, sign, x_len = mpx[0]; long w_len = x_len + 1; mp mpv; mp_set_length(w_len, mpw); mpv = *mpw; for (i = 1; i <= w_len; i++) { s = mpx[i] + c; mpv[i] = s % BASE; c = s < BASE ? 0 : 1; } sign = mpv[w_len + 1]; for (i = w_len, zero = mpv[w_len] == 0; i >= 3 && zero; i--) zero = mpv[i - 1] == 0, mpv[0]--; mpv[mpv[0] + 1] = sign;

void mp_base_left_shift(mp mpa, long count, mp *mpb) { long i, length = mpa[0]; mp mpc; mp_set_length(length + count, mpb); mpc = *mpb; for (i = 1; i <= count; i++)

mpc[i] = 0; for (i = 1; i <= length; i++) mpc[i + count] = mpa[i];

void mp_div(mp mpx, mp mpy, mp *mpq, mp *mpr) /* calcuates q = x / y, r = x % y */ { int zero = 1; long c, l, qj, sign, u, uv, v, xi, xi1, xi2, yt, yt1; long i, j, k, x_len = mpx[0], y_len = mpy[0]; long a_len, q_len = x_len - y_len + 1, r_len = y_len; long x_sign = mpx[x_len + 1], y_sign = mpy[y_len + 1]; mp mpa = 0, mpb = 0, mpc = 0, mpd = 0, mpe = 0; mp mpu, mpv, mpw = 0; /* test for zero divisor */ for (i = y_len; i >= 1 && zero; i--) zero = mpy[i] == 0; assert(zero == 0); mp_copy(mpx, &mpa); mp_copy(mpy, &mpb); if (x_sign != 0) mp_negate(&mpa); if (y_sign != 0) mp_negate(&mpb); /* check for dividend < divisor */ if (mp_compare(mpa, mpb) < 0) { mp_set_length(1, mpq); (*mpq)[1] = 0; if (mpx[x_len + 1] == 0) mp_copy(mpx, mpr); else mp_add(mpx, mpy, mpr); } else { mp_set_length(q_len, mpq); mp_set_length(r_len, mpr); mpu = *mpq; mp_base_left_shift(mpb, x_len - y_len, &mpc); while (mp_compare(mpa, mpc) >= 0) { mpu[q_len]++; mp_sub(mpa, mpc, &mpd); mp_copy(mpd, &mpa); } #ifdef DEBUG for (j = mpu[0]; j >= 1; j--) printf("%ld", mpu[j]); printf(" "); for (j = mpa[0]; j >= 1; j--) printf("%ld", mpa[j]); printf("\n"); #endif for (i = mpa[0], zero = mpa[i] == 0; i >= 1 && zero; i--) zero = mpa[i - 1] == 0, mpa[0]--; mpa[mpa[0] + 1] = 0; yt = mpb[y_len]; yt1 = mpb[y_len - 1]; for (i = x_len; i >= y_len + 1; i--) {

j = i - y_len; a_len = mpa[0]; if (i <= a_len) xi = mpa[i]; else xi = 0; if (i - 1 <= a_len) xi1 = mpa[i - 1]; else xi1 if (i - 2 <= a_len) xi2 = mpa[i - 2]; else xi2 if (xi == yt) qj = BASE - 1; else qj = (BASE * xi + xi1) / yt; while (qj * (yt * BASE + yt1) > xi * BASE * BASE + xi1 * BASE + xi2) qj--; if (qj != 0) { mp_base_left_shift(mpb, j - 1, &mpc); c = 0; l = mpc[0]; mp_set_length(l + 1, &mpw); for (k = 1; k <= l; k++) { uv = mpw[k] + qj * mpc[k] + c; u = uv / BASE; v = uv % BASE; mpw[k] = v; c = u; } mpw[l + 1] = u; mp_sub(mpa, mpw, &mpd); if (mpd[mpd[0] + 1] != 0) { mp_add(mpa, mpc, &mpe); mp_copy(mpe, &mpd); qj--; } mp_copy(mpd, &mpa); } mpu[j] = qj; for (j = mpu[0], zero = mpu[j] == 0; j >= 1 && zero = mpu[j - 1] == 0, mpu[0]--; for (j = mpa[0], zero = mpa[j] == 0; j >= 1 && zero = mpa[j - 1] == 0, mpa[0]--; mpu[mpu[0] + 1] = 0; mpa[mpa[0] + 1] = 0; #ifdef DEBUG for (j = mpu[0]; j >= 1; j--) printf("%ld", mpu[j]); printf(" "); for (j = mpa[0]; j >= 1; j--) printf("%ld", mpa[j]); printf("\n"); #endif

= 0; = 0;

zero; j--) zero; j--)

} mp_copy(mpa, mpr); for (i = q_len, zero = mpu[q_len] == 0; i >= 3 && zero; i--) zero = mpu[i - 1] == 0, q_len--; mpu[0] = q_len; mpu[q_len + 1] = 0; if (x_sign != 0 && y_sign == 0) { mp_adds(*mpq, 1l, &mpc); mp_copy(mpc, mpq);

} else if (x_sign == 0 && y_sign != 0) { mp_adds(*mpq, 1l, &mpc); mp_copy(mpc, mpq); mp_negate(mpq); mp_add(*mpr, mpy, &mpc); mp_copy(mpc, mpr); mpv = *mpr; sign = mpv[r_len + 1]; for (i = r_len, zero = mpv[r_len] == 0; i >= 3 && zero; i--) zero = mpv[i - 1] == 0, r_len--; mpv[0] = r_len; mpv[r_len + 1] = sign; } else if (x_sign != 0 && y_sign != 0) { mp_negate(mpr); mpv = *mpr; sign = mpv[r_len + 1]; for (i = r_len, zero = mpv[r_len] == 0; i >= 3 && zero; i--) zero = mpv[i - 1] == 0, r_len--; mpv[0] = r_len; mpv[r_len + 1] = sign; } } mp_free(&mpa); mp_free(&mpb); mp_free(&mpc); mp_free(&mpd); mp_free(&mpe); mp_free(&mpw);

mp_negate(mpq); mp_negate(mpr); mp_add(*mpr, mpb, &mpc); mp_copy(mpc, mpr); mpv = *mpr; for (i = r_len, zero = mpv[r_len] == 0; i >= 3 && zero; i--) zero = mpv[i - 1] == 0, r_len--; mpv[0] = r_len; mpv[r_len + 1] = 0;

void mp_mul(mp mpx, mp mpy, mp *mpw) /* calcuates w = x * y */ { long c, i, ij, j, x_len = mpx[0], y_len = mpy[0]; long u, uv, v, w_len = x_len + y_len + 2, w_sign; long x_sign = mpx[x_len + 1], y_sign = mpy[y_len + 1]; mp mpa = 0, mpb = 0, mpv; mp_copy(mpx, &mpa); mp_copy(mpy, &mpb); if (x_sign != 0) mp_negate(&mpa); if (y_sign != 0) mp_negate(&mpb); w_sign = (x_sign == y_sign) ? 0 : BASE - 1; mp_set_length(w_len, mpw); mpv = *mpw; for (i = 1; i <= y_len; i++) {

c = 0; for (j = 1; j <= x_len; j++) { ij = i + j - 1; uv = mpv[ij] + mpa[j] * mpb[i] + c; u = uv / BASE; v = uv % BASE; mpv[ij] = v; c = u; } mpv[i + x_len] = u; } for (i = w_len; i >= 1 && mpv[i] == 0; i--) mpv[0]--; if (w_sign != 0) mp_negate(mpw); mp_free(&mpa); mp_free(&mpb);

int mp_odd(mp mpa) /* returns nonzero if a is odd */ { return (int) (mpa[1] & 1l); } void mp_one(mp *mpa) /* a = 1 */ { mp_set_length(1, mpa); (*mpa)[1] = 1; } void mp_zero(mp *mpa) /* a = 0 */ { mp_set_length(1, mpa); } void mp_long_to_mp(long l, mp *mpa) { long digits[256], i = 0, j, sign = l < 0; if (sign) l = - l; do { digits[i++] = l % BASE; l /= BASE; } while (l > 0); mp_set_length(i, mpa); for (j = 1; j <= i; j++) (*mpa)[j] = digits[j - 1]; if (sign) mp_negate(mpa); } void mp_print(mp mpa) { char digits[2048]; long count, i = 0, j, k, left, sign = 0; mp mpb = 0, mpc = 0, mpq = 0, mpr = 0; mp_copy(mpa, &mpb);

if (mpb[mpb[0] + 1] != 0) { sign = 1; mp_negate(&mpb); } mp_long_to_mp(10l, &mpc); do { mp_div(mpb, mpc, &mpq, &mpr); digits[i++] = (char) (mpr[1] + '0'); mp_copy(mpq, &mpb); } while (mp_compares(mpq, 0l) > 0); digits[i] = 0; strrev(digits); count = i / DIGITS_PER_LINE; left = i % DIGITS_PER_LINE; if (sign == 1) printf("-"); for (i = 0; i < count; i++) { j = i * DIGITS_PER_LINE; for (k = 0; k < DIGITS_PER_LINE; k++) printf("%c", digits[j + k]); printf("\\\n"); } i = count * DIGITS_PER_LINE; for (j = 0; j < left; j++) printf("%c", digits[i + j]); printf("\n"); mp_free(&mpb); mp_free(&mpc); mp_free(&mpq); mp_free(&mpr);

int main(void) { mp mpq = 0, mpr = 0, mpx = 0, mpy = 0; mp_set_length(9, &mpx); mp_set_length(5, &mpy); mpx[1] = 7, mpx[2] = 2, mpx[3] = 3, mpx[4] = 8; mpx[5] = 4, mpx[6] = 9, mpx[7] = 1, mpx[8] = 2, mpx[9] = 7; mpy[1] = 1, mpy[2] = 6, mpy[3] = 4, mpy[4] = 4, mpy[5] = 8; mp_div(mpx, mpy, &mpq, &mpr); mp_dump(mpx); mp_dump(mpy); mp_dump(mpq); mp_dump(mpr); mp_negate(&mpx); mp_div(mpx, mpy, &mpq, &mpr); mp_dump(mpx); mp_dump(mpy); mp_dump(mpq); mp_dump(mpr); mp_negate(&mpx); mp_negate(&mpy); mp_div(mpx, mpy, &mpq, &mpr); mp_dump(mpx); mp_dump(mpy); mp_dump(mpq);

mp_dump(mpr); mp_negate(&mpx); mp_div(mpx, mpy, &mpq, &mpr); mp_dump(mpx); mp_dump(mpy); mp_dump(mpq); mp_dump(mpr); mp_free(&mpq); mp_free(&mpr); mp_free(&mpx); mp_free(&mpy); return 0; }

14.32 Algorithm Montgomery reduction monty.c freelip (1,947)


/* Author: Pate Williams (c) 1997

Montgomery reduction. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al Section 14.3.2 pages 600 - 603. */ #include <malloc.h> #include <stdio.h> #include "lip.h" #define DEBUG void radix_representation(long b, long n, long *a, verylong za) { long i = 0; verylong zb = 0, zq = 0, zr = 0, zx = 0; zintoz(b, &zb); zcopy(za, &zx); do { zdiv(zx, zb, &zq, &zr); a[i++] = ztoint(zr); zcopy(zq, &zx); } while (zscompare(zq, 0l) != 0); while (i < n) a[i++] = 0; zfree(&zb); zfree(&zq); zfree(&zr); zfree(&zx);

void Montgomery_reduction(long b, long n, verylong zR, verylong zT, verylong zm, verylong *zA) { long *a, i, n2 = 2 * n; verylong za = 0, zb = 0, zc = 0, zd = 0, ze = 0; verylong zu = 0, zmp = 0;

a = malloc(n2 * sizeof(long)); radix_representation(b, n2, a, zT); zintoz(b, &zb); zinvmod(zm, zb, &za); znegate(&za); zmod(za, zb, &zmp); zone(&zc); #ifdef DEBUG zwriteln(zmp); #endif zcopy(zT, zA); for (i = 0; i < n; i++) { zintoz(a[i], &za); zmulmod(za, zmp, zb, &zu); zmul(zu, zm, &zd); zmul(zc, zd, &ze); zadd(*zA, ze, &za); zcopy(za, zA); zmul(zb, zc, &zd); zcopy(zd, &zc); #ifdef DEBUG printf("%ld ", i); zwrite(zu); printf(" "); zwrite(ze); printf(" "); zwriteln(*zA); #endif radix_representation(b, n2, a, *zA); } zdiv(*zA, zR, &za, &zb); zcopy(za, zA); free(a); zfree(&za); zfree(&zb); zfree(&zc); zfree(&zd); zfree(&ze); zfree(&zu); zfree(&zmp);

int main(void) { long b = 10, n = 5; verylong zA = 0, zR = 0, zT = 0, zm = 0; zintoz(100000l, &zR); zintoz(7118368l, &zT); zintoz(72639l, &zm); Montgomery_reduction(b, n, zR, zT, zm, &zA); zwriteln(zA); return 0; }

14.36
/*

Algorithm Montgomery multiplication montmult.c freelip (2,333)

Author:

Pate Williams (c) 1997

*/

Montgomery multiplication. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al Section 14.3.2 pages 600 - 603.

#include <stdio.h> #include <stdlib.h> #include "lip.h" #define DEBUG void radix_representation(long b, long n, long *a, verylong za) { long i = 0; verylong zb = 0, zq = 0, zr = 0, zx = 0; zintoz(b, &zb); zcopy(za, &zx); do { zdiv(zx, zb, &zq, &zr); a[i++] = ztoint(zr); zcopy(zq, &zx); } while (zscompare(zq, 0l) != 0); while (i < n) a[i++] = 0; zfree(&zb); zfree(&zq); zfree(&zr); zfree(&zx); } void Montgomery_multiplication(long b, long n, verylong zm, verylong zx, verylong zy, verylong *zA) { long i, n1 = n + 1, u, mp, *a, *m, *x, *y; verylong za = 0, zb = 0, zc = 0, zd = 0, zs = 0; a = calloc(n1, sizeof(long)); m = calloc(n1, sizeof(long)); x = calloc(n1, sizeof(long)); y = calloc(n1, sizeof(long)); if (a == 0 || m == 0 || x == 0 || y == 0) { printf("*error*\ncan't get memory from Montgomery"); printf(" multiplication"); exit(1); } zintoz(b, &zb); zinvmod(zm, zb, &za); znegate(&za); mp = zsmod(za, b); radix_representation(b, n1, m, zm); radix_representation(b, n1, x, zx); radix_representation(b, n1, y, zy); zzero(zA); for (i = 0; i < n; i++) {

} if (zcompare(*zA, zm) >= 0) { zsub(*zA, zm, &za); zcopy(za, zA); } free(a); free(m); free(x); free(y); zfree(&za); zfree(&zb); zfree(&zc); zfree(&zd); zfree(&zs);

radix_representation(b, n1, a, *zA); u = ((a[0] + x[i] * y[0]) * mp) % b; zsmul(zy, x[i], &za); zsmul(zm, u, &zc); zadd(*zA, za, &zs); zadd(zs, zc, &zd); zsdiv(zd, b, zA); #ifdef DEBUG printf("%ld %ld %ld %ld ", i, x[i], x[i] * y[0], u); zwrite(za); printf(" "); zwrite(zc); printf(" "); zwriteln(*zA); #endif

int main(void) { long b = 10, n = 5; verylong zA = 0, zm = 0, zx = 0, zy = 0; zintoz(72639l, &zm); zintoz(5792l, &zx); zintoz(1229l, &zy); Montgomery_multiplication(b, n, zm, zx, zy, &zA); zwriteln(zA); zfree(&zA); zfree(&zm); zfree(&zx); zfree(&zy); return 0; }

14.42 Algorithm Barrett modular reduction barrett.c freelip (2,732)


/* Author: Pate Williams (c) 1997

Barrett modular reduction. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al 14.3.3 Section pages 603 - 604. */

#include <stdio.h> #include "lip.h" #define DEBUG #ifdef DEBUG void radix_representation(long b, long n, long *a, verylong za) { long i = 0; verylong zb = 0, zq = 0, zr = 0, zx = 0; zintoz(b, &zb); zcopy(za, &zx); do { zdiv(zx, zb, &zq, &zr); a[i++] = ztoint(zr); zcopy(zq, &zx); } while (zscompare(zq, 0l) != 0); while (i < n) a[i++] = 0; zfree(&zb); zfree(&zq); zfree(&zr); zfree(&zx);

} #endif

void Barrett_reduction(long b, long k, verylong zm, verylong zmu, verylong zx, verylong *zr) { verylong zb = 0, zbk = 0, zq1 = 0, zq2 = 0, zq3 =0; verylong zr1 = 0, zr2 = 0; zintoz(b, &zb); zsexp(zb, k - 1, &zbk); zdiv(zx, zbk, &zq1, &zq2); zmul(zq1, zmu, &zq2); zsexp(zb, k + 1, &zbk); zdiv(zq2, zbk, &zq3, &zr1); zmod(zx, zbk, &zr1); zmulmod(zq3, zm, zbk, &zr2); zsub(zr1, zr2, zr); if (zscompare(*zr, 0l) < 0) { zadd(*zr, zbk, &zb); zcopy(zb, zr); } #ifdef DEBUG { long a[256], i, k2 = (k + 1) * 2; radix_representation(b, k2, a, zq1); printf("q1 = "); for (i = k2 - 1; i >= 0; i--) printf("%ld", a[i]); printf(" = "); zwriteln(zq1); radix_representation(b, k2, a, zq2);

} #endif while (zcompare(*zr, zm) >= 0) { zsub(*zr, zm, &zb); zcopy(zb, zr); } zfree(&zb); zfree(&zbk); zfree(&zq1); zfree(&zq2); zfree(&zq3); zfree(&zr1); zfree(&zr2); } int main(void) { verylong zm = 0, zmu = 0, zr = 0, zx = 0; zintoz(47l, &zm); zintoz(87l, &zmu); zintoz(3561l, &zx); Barrett_reduction(4, 3, zm, zmu, zx, &zr); zfree(&zm); zfree(&zmu); zfree(&zr); zfree(&zx); return 0;

printf("q2 = "); for (i = k2 - 1; i >= 0; i--) printf("%ld", a[i]); printf(" = "); zwriteln(zq2); radix_representation(b, k2, a, printf("q3 = "); for (i = k2 - 1; i >= 0; i--) printf("%ld", a[i]); printf(" = "); zwriteln(zq3); radix_representation(b, k2, a, printf("r1 = "); for (i = k2 - 1; i >= 0; i--) printf("%ld", a[i]); printf(" = "); zwriteln(zr1); radix_representation(b, k2, a, printf("r2 = "); for (i = k2 - 1; i >= 0; i--) printf("%ld", a[i]); printf(" = "); zwriteln(zr2); radix_representation(b, k2, a, printf("r = "); for (i = k2 - 1; i >= 0; i--) printf("%ld", a[i]); printf(" = "); zwriteln(*zr);

zq3);

zr1);

zr2);

*zr);

14.54
/* Author:

Algorithm Binary gcd algorithm bingcd.c (904)


Pate Williams (c) 1997

14.54 Algorithm Binary gcd algorithm See "Handbook of Applied Cryptography" by Alfred J. Menezes et al page 606. */ #include <math.h> #include <stdio.h> #define DEBUG long binary_gcd(long x, long y) { long g = 1, t; #ifdef DEBUG printf("-----------\n"); printf(" x y g\n"); printf("-----------\n"); #endif while (!(x & 1) && !(y & 1)) x >>= 1, y >>= 1, g <<= 1; while (x != 0) { while (!(x & 1)) x >>= 1; while (!(y & 1)) y >>= 1; t = labs(x - y) >> 1; if (x >= y) x = t; else y = t; #ifdef DEBUG printf("%3ld %3ld %3ld\n", x, y, g); #endif } #ifdef DEBUG printf("-----------\n"); #endif return g * y; } int main(void) { long x = 1764, y = 868; printf("x = %ld y = %ld\n", x, y); printf("gcd(x, y) = %ld\n", binary_gcd(x, y)); return 0;

14.57
/* Author:

Algorithm Lehmer's gcd algorithm lehmer.c freelip (2,527)


Pate Williams (c) 1997

14.57 Algorithm Lehmer's gcd algorithm

See "Handbook of Applied Cryptography" by Alfred J. Menezes et al page 607. */ #include <stdio.h> #include "lip.h" #define DEBUG void radix_representation(long b, verylong zx, long *a, long *t) { long i = 0; verylong za = 0, zq = 0, zr = 0; zcopy(zx, &za); a[i++] = zsdiv(za, b, &zq); while (zscompare(zq, 0l) > 0) { zcopy(zq, &za); a[i++] = zsdiv(zq, b, &zr); zcopy(zr, &zq); } *t = i; zfree(&za); zfree(&zq); zfree(&zr); } void Lehmer_gcd(long b, verylong zx, verylong zy, verylong *zv) { long A, B, C, D, q, qp, t; long xp, xt, yp, yt, xa[4096], ya[4096]; verylong zT = 0, za = 0, zb = 0, zc = 0, zd = 0; verylong zu = 0; zcopy(zx, &za); zcopy(zy, &zb); while (zscompare(zb, b) > 0) { radix_representation(b, za, xa, &xt); radix_representation(b, zb, ya, &yt); xp = xa[xt - 1]; yp = ya[yt - 1]; A = D = 1, B = C = 0; if (xt == yt) { while (yp + C != 0 && yp + D != 0) { q = (xp + A) / (yp + C); qp = (xp + B) / (yp + D); #ifdef DEBUG printf("%3ld %3ld %2ld %2ld %2ld %2ld %2ld %2ld\n", xp, yp, A, B, C, D, q, qp); #endif if (q != qp) break; t = A - q * C, A = C, C = t; t = B - q * D, B = D, D = t; t = xp - q * yp, xp = yp, yp = t; }

} while (zcompare(zb, 0l) > 0) { zmod(za, zb, &zu); zcopy(zb, &za); zcopy(zu, &zb); #ifdef DEBUG zwrite(za); printf(" "); zwriteln(zb); #endif } zcopy(za, zv); zfree(&zT); zfree(&za); zfree(&zb); zfree(&zc); zfree(&zd); zfree(&zu);

} if (B == 0) { zmod(za, zb, &zT); zcopy(zb, &za); zcopy(zT, &zb); } else { zsmul(za, A, &zc); zsmul(zb, B, &zd); zadd(zc, zd, &zT); zsmul(za, C, &zc); zsmul(zb, D, &zd); zadd(zc, zd, &zu); zcopy(zT, &za); zcopy(zu, &zb); } #ifdef DEBUG zwrite(za); printf(" "); zwriteln(zb); #endif

int main(void) { long b = 1000; verylong zv = 0, zx = 0, zy = 0; zintoz(768454923l, &zx); zintoz(542167814l, &zy); Lehmer_gcd(b, zx, zy, &zv); printf("x = "); zwriteln(zx); printf("y = "); zwriteln(zy); printf("gcd(x, y) = "); zwriteln(zv); zfree(&zv); zfree(&zx); zfree(&zy); return 0; }

14.61

Algorithm Binary extended gcd algorithm binegcd.c freelip (2,808)

/*

Author:

Pate Williams (c) 1997

Extended binary Euclid algorithm. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al Section 14.4.3 pages 608 - 610. */ #include <stdio.h> #include "lip.h" #define DEBUG void zbinary_ext_gcd(verylong verylong verylong /* returns a * x + b * y = v, { verylong zA = 0, zB = 0, zC verylong zX = 0, zY = 0, zc verylong zu = 0; zx, verylong zy, *za, verylong *zb, *zv) v = gcd(x, y) */ = 0, zD = 0; = 0, zg = 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); } #ifdef DEBUG zwrite(zu); printf(" "); zwrite(*zv); printf(" "); zwrite(zA); printf(" "); zwrite(zB); printf(" "); zwrite(zC); printf(" "); zwriteln(zD); #endif } 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);

int main(void) {

verylong za = 0, zb = 0, zv = 0, zx = 0, zy = 0; zintoz(693l, &zx); zintoz(609l, &zy); zbinary_ext_gcd(zx, zy, &za, &zb, &zv); printf("a = "); zwriteln(za); printf("b = "); zwriteln(zb); printf("v = "); zwriteln(zv); zfree(&za); zfree(&zb); zfree(&zv); zfree(&zx); zfree(&zy); return 0; }

14.71
/* Author:

Algorithm Garner's algorithm for CRT garner.c freelip (5,059)


Pate Williams (c) 1997

14.71 Algorithm Garner's Algorithm for CRT See "Handbook of Applied Cryptography" by Alfred J. Menezes et al page 612. */ #include #include #include #include <stdio.h> <stdlib.h> <time.h> "lip.h"

#define CRT_SIZE 8192l 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);

} zfree(&za); zfree(&zb); zfree(&zu); for (i = 0; i < CRT_SIZE; i++) zfree(&zC[i]); } long OddRandom(long bit_length) { long i, mask = 1, n; bit_length--; for (i = 1; i <= bit_length; i++) mask |= 1 << i; if (bit_length < 16) n = (1 << bit_length) | rand(); else n = (1 << bit_length) | (rand() << 16) | rand(); n &= mask; if ((n & 1) == 0) n++; return n; } void PROVABLE_PRIME(long k, verylong *zn) { double c, r, s; int success; long B, m, n, p, sqrtn; verylong zI = 0, zR = 0, za = 0, zb = 0, zc = 0; verylong zd = 0, zk = 0, zl = 0, zq = 0, zu = 0; if (k <= 20) { do { n = OddRandom(k); sqrtn = sqrt(n); zpstart2(); do p = zpnext(); while (n % p != 0 && p < sqrtn); } while (p < sqrtn); zintoz(n, zn); } else { c = 0.1; m = 20; B = c * k * k; if (k > 2 * m) do { s = rand() / (double) RAND_MAX; r = pow(2.0, s - 1.0); } while (k - r * k <= m); else r = 0.5; PROVABLE_PRIME(r * k + 1, &zq);

zcopy(zb, &za); } zmul(za, zu, &zb); zadd(*zx, zb, &za); zcopy(za, zx);

} zfree(&zI); zfree(&zR); zfree(&za); zfree(&zb); zfree(&zc); zfree(&zd); zfree(&zk); zfree(&zl); zfree(&zq); zfree(&zu); }

zone(&za); zlshift(za, k - 1, &zk); zcopy(zq, &za); zlshift(za, 1l, &zl); zdiv(zk, zl, &zI, &za); zsadd(zI, 1l, &zl); zlshift(zI, 1l, &zu); success = 0; while (!success) { do zrandomb(zu, &zR); while (zcompare(zR, zl) < 0); zmul(zR, zq, &za); zlshift(za, 1l, &zb); zsadd(zb, 1l, zn); zcopy(zR, &za); zlshift(za, 1l, &zR); zpstart2(); p = zpnext(); while (zsmod(*zn, p) != 0 && p < B) p = zpnext(); if (p >= B) { zcopy(*zn, &zc); zsadd(zc, - 2l, &zb); do zrandomb(*zn, &za); while (zscompare(za, 2l) < 0 || zcompare(za, zb) > 0); zsadd(*zn, - 1l, &zc); zexpmod(za, zc, *zn, &zb); if (zscompare(zb, 1l) == 0) { zexpmod(za, zR, *zn, &zb); zcopy(zb, &zd); zsadd(zd, - 1l, &zb); zgcd(zb, *zn, &zd); success = zscompare(zd, 1l) == 0; } } }

void RSA_gen_keys(long length, verylong *zd, verylong *ze, verylong *zp, verylong *zq) { verylong zp1 = 0, zq1 = 0; verylong zphi = 0, zx = 0; srand(time(NULL)); zrstarts(time(NULL));

PROVABLE_PRIME(length, zp); PROVABLE_PRIME(length, zq); zsadd(*zp, - 1l, &zp1); zsadd(*zq, - 1l, &zq1); zmul(zp1, zq1, &zphi); do { do zrandomb(zphi, ze); while (zscompare(*ze, 1l) <= 0); zgcd(*ze, zphi, &zx); } while (zscompare(zx, 1l) != 0); zinvmod(*ze, zphi, zd); zfree(&zp1); zfree(&zq1); zfree(&zphi); zfree(&zx); } void RSA_exponentiation(verylong verylong verylong { verylong zdp = 0, zdq = 0, zp1 verylong zm[2], zv[2]; zx, verylong zd, zp, verylong zq, *zM) = 0, zq1 = 0;

zsadd(zp, - 1l, &zp1); zsadd(zq, - 1l, &zq1); zmod(zd, zp1, &zdp); zmod(zd, zq1, &zdq); zm[0] = zm[1] = zv[0] = zv[1] = 0; zcopy(zp, &zm[0]); zcopy(zq, &zm[1]); zexpmod(zx, zdp, zp, &zv[0]); zexpmod(zx, zdq, zq, &zv[1]); Garner(2l, zm, zv, zM); zfree(&zdp); zfree(&zdq); zfree(&zp1); zfree(&zq1); zfree(&zm[0]); zfree(&zm[1]); zfree(&zv[0]); zfree(&zv[1]);

int main(void) { verylong zM = 0, zN = 0, zd = 0, ze = 0, zn = 0; verylong zp = 0, zq = 0, zx = 0; RSA_gen_keys(128l, &zd, &ze, &zp, &zq); zintoz(65537l, &zx); RSA_exponentiation(zx, zd, zp, zq, &zM); zmul(zp, zq, &zn); zexpmod(zx, zd, zn, &zN); if (zcompare(zM, zN) == 0) printf("RSA_exponentiation confirmed\n"); else printf("*error*\nin RSA_exponentiation\n");

zfree(&zM); zfree(&zN); zfree(&zd); zfree(&ze); zfree(&zn); zfree(&zp); zfree(&zq); zfree(&zx); return 0;

14.82
/* Author:

Algorithm Left-to-right k-ary exponentiation ltrkary.c freelip (1,482)


Pate Williams (c) 1997

*/

Left-to-right k-ary exponentiation. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al 14.6.1 Section pages 614 - 616. <math.h> <stdio.h> <stdlib.h> "lip.h"

#include #include #include #include

#define DEBUG void radix_representation(long b, long *a, long *t, verylong za) { long i = 0; verylong zb = 0, zq = 0, zr = 0, zx = 0; zintoz(b, &zb); zcopy(za, &zx); do { zdiv(zx, zb, &zq, &zr); a[i++] = ztoint(zr); zcopy(zq, &zx); } while (zscompare(zq, 0l) != 0); *t = i; zfree(&zb); zfree(&zq); zfree(&zr); zfree(&zx);

void ltr_k_ary(long b, verylong ze, verylong zg, verylong *zA) { long e[8192], i, t; verylong za = 0, *zg1; radix_representation(b, e, &t, ze); #ifdef DEBUG for (i = t - 1; i >= 0; i--)

printf("%d", e[i]); printf("\n"); #endif zg1 = calloc(b, sizeof(verylong)); zone(&zg1[0]); for (i = 1; i < b; i++) zmul(zg1[i - 1], zg, &zg1[i]); zone(zA); for (i = t - 1; i >= 0; i--) { zsexp(*zA, b, &za); zmul(za, zg1[e[i]], zA); } free(zg1); zfree(&za); } int main(void) { long b, e = 127l, k = 1l; verylong zA = 0, za = 0, ze = 0, zg = 0; b = pow(2, k); zintoz(2l, &zg); zintoz(e, &ze); ltr_k_ary(b, ze, zg, &zA); zwriteln(zA); zexp(zg, ze, &za); zwriteln(za); zfree(&zA); zfree(&za); zfree(&ze); zfree(&zg); return 0;

14.83
/* Author:

Algorithm Modified left-to-right k-ary exponentiation mltrkary.c freelip (2,441)


Pate Williams (c) 1997

*/

Modified left-to-right k-ary exponentiation. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al 14.6.1 Section pages 614 - 616. <math.h> <stdio.h> <stdlib.h> "lip.h"

#include #include #include #include

#define DEBUG void radix_representation(long b, long *a, long *t, verylong za) { long i = 0;

verylong zb = 0, zq = 0, zr = 0, zx = 0; zintoz(b, &zb); zcopy(za, &zx); do { zdiv(zx, zb, &zq, &zr); a[i++] = ztoint(zr); zcopy(zq, &zx); } while (zscompare(zq, 0l) != 0); *t = i; zfree(&zb); zfree(&zq); zfree(&zr); zfree(&zx); } void mltr_k_ary(long b, long k, verylong ze, verylong zg, verylong *zA) { long i, j, l, t; long e[8192], h[8192], u[8192]; verylong za = 0, zb = 0, zc = 0, *zg1; radix_representation(b, e, &t, ze); #ifdef DEBUG for (i = t - 1; i >= 0; i--) printf("%ld", e[i]); printf("\n"); #endif for (i = 0; i < t; i++) { j = e[i]; if (j == 0) h[i] = u[i] = 0; else if (j & 1) h[i] = 0, u[i] = j; else { l = 0; while (!(j & 1)) j >>= 1, l++; h[i] = l, u[i] = j; } } #ifdef DEBUG for (i = t - 1; i >= 0; i--) printf("%ld", h[i]); printf("\n"); for (i = t - 1; i >= 0; i--) printf("%ld", u[i]); printf("\n"); #endif zg1 = calloc(b + 2, sizeof(verylong)); zone(&zg1[0]); zcopy(zg, &zg1[1]); zsq(zg, &zg1[2]); for (i = 1; i <= b / 2 - 1; i++) zmul(zg1[2 * i - 1], zg1[2], &zg1[2 * i + 1]); zone(zA); for (i = t - 1; i >= 0; i--) { zsexp(*zA, pow(2, k - h[i]), &za); zmul(za, zg1[u[i]], &zb);

} free(zg1); zfree(&za); zfree(&zb); zfree(&zc); }

if (h[i] == 0) zcopy(zb, zA); else zsexp(zb, pow(2, h[i]), zA);

int main(void) { long b = 8l, k = 3l; verylong zA = 0, za = 0, ze = 0, zg = 0; zintoz(116l, &ze); zintoz(2l, &zg); mltr_k_ary(b, k, ze, zg, &zA); zwriteln(zA); zsexp(zg, 116l, &za); zwriteln(za); zintoz(127l, &ze); zintoz(2l, &zg); mltr_k_ary(b, k, ze, zg, &zA); zwriteln(zA); zsexp(zg, 127l, &za); zwriteln(za); b = 2l, k = 1l; zintoz(129l, &ze); zintoz(2l, &zg); mltr_k_ary(b, k, ze, zg, &zA); zwriteln(zA); zsexp(zg, 129l, &za); zwriteln(za); zfree(&zA); zfree(&za); zfree(&ze); zfree(&zg); return 0;

14.85
/*

Algorithm Sliding window exponentiation swindow.c freelip (2,190)


Pate Williams (c) 1997

Author:

*/

Sliding window exponentiation. See "Handboook of Applied Cryptography" by Alfred J. Menezes et al 14.6.1 Section pages 614 - 620. <math.h> <stdio.h> <stdlib.h> <string.h>

#include #include #include #include

#include "lip.h" #define DEBUG void long_to_binary(char *e, long a, long *t) { long i; *t = z2logs(a); for (i = 0; i < *t; i++) { e[i] = (char) (a & 1); a >>= 1; }

long binary_to_long(char *e, long i, long l) { long a, t; a = e[i]; for (t = i - 1; t >= l; t--) a = (a << 1) + e[t]; return a;

void sliding_window(long exp, long k, verylong zg, verylong *zA) { char e[32]; long i, l, length, limit, m, t; verylong za = 0, zb = 0; verylong zg1 = 0, zg2 = 0, *zg3; limit = pow(2, k - 1) - 1; length = 2 * limit + 2; zg3 = calloc(length, sizeof(verylong)); long_to_binary(e, exp, &t); #ifdef DEBUG for (i = t - 1; i >= 0; i--) printf("%d", e[i]); printf("\n"); #endif zcopy(zg, &zg1); zsq(zg, &zg2); for (i = 1; i <= limit; i++) zmul(zg2, zg3[2 * i - 1], &zg3[2 * i + 1]); zone(zA); i = t - 1; while (i >= 0) { if (e[i] == 0) { zsq(*zA, &za); zcopy(za, zA); i--; } else { l = i - 1; while (i - l + 1 <= k && l >= 0) {

if (e[l] == 1) m = l; l--; } if (i - l + 1 > k) { zmul(*zA, *zA, &za); zmul(za, zg, zA); i = i - 1; } else { l = m; zsexp(*zA, pow(2, i - l + 1), &za); #ifdef DEBUG printf("%ld %ld %ld\n", i, l, binary_to_long(e, i, l)); #endif zsexp(zg, binary_to_long(e, i, l), &zb); zmul(za, zb, zA); i = l - 1; } } } zfree(&za); zfree(&zb); zfree(&zg1); zfree(&zg2); for (i = 0; i < length; i++) zfree(&zg3[i]);

int main(void) { long exp = 39l; verylong zA = 0, zg = 0; zintoz(2l, &zg); sliding_window(exp, 3l, zg, &zA); zwriteln(zA); zsexp(zg, exp, &zA); zwriteln(zA); zfree(&zA); zfree(&zg); return 0; }

14.94
/* Author:

Algorithm Montgomery exponentiation montexpo.c freelip (3,032)


Pate Williams (c) 1997

Montgomery exponentiation. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al Section 14.6.1 pages 614 - 620. */ #include <stdio.h> #include <stdlib.h> #include "lip.h" #define DEBUG

void radix_representation(long b, long n, long *a, verylong za) { long i = 0; verylong zb = 0, zq = 0, zr = 0, zx = 0; zintoz(b, &zb); zcopy(za, &zx); do { zdiv(zx, zb, &zq, &zr); a[i++] = ztoint(zr); zcopy(zq, &zx); } while (zscompare(zq, 0l) != 0); while (i < n) a[i++] = 0; zfree(&zb); zfree(&zq); zfree(&zr); zfree(&zx); } void Montgomery_multiplication(long b, long n, verylong zm, verylong zx, verylong zy, verylong *zA) { long i, n1 = n + 1, u, mp, *a, *m, *x, *y; verylong za = 0, zb = 0, zc = 0, zd = 0, zs = 0; a = calloc(n1, sizeof(long)); m = calloc(n1, sizeof(long)); x = calloc(n1, sizeof(long)); y = calloc(n1, sizeof(long)); if (a == 0 || m == 0 || x == 0 || y == 0) { printf("*error*\ncan't get memory from Montgomery"); printf(" multiplication"); exit(1); } zintoz(b, &zb); zinvmod(zm, zb, &za); znegate(&za); mp = zsmod(za, b); radix_representation(b, n1, m, zm); radix_representation(b, n1, x, zx); radix_representation(b, n1, y, zy); zzero(zA); for (i = 0; i < n; i++) { radix_representation(b, n1, a, *zA); u = ((a[0] + x[i] * y[0]) * mp) % b; zsmul(zy, x[i], &za); zsmul(zm, u, &zc); zadd(*zA, za, &zs); zadd(zs, zc, &zd); zsdiv(zd, b, zA); } if (zcompare(*zA, zm) >= 0) { zsub(*zA, zm, &za); zcopy(za, zA); }

free(a); free(m); free(x); free(y); zfree(&za); zfree(&zb); zfree(&zc); zfree(&zd); zfree(&zs);

void Montgomery_exponentiation(char *e, long b, long l, long t, verylong zR, verylong zm, verylong zx, verylong *zA) { long i; verylong za = 0, zb = 0, zxp = 0; zmulmod(zR, zR, zm, &zb); Montgomery_multiplication(b, l, zm, zx, zb, &zxp); zmod(zR, zm, zA); for (i = t; i >= 0; i--) { Montgomery_multiplication(b, l, zm, *zA, *zA, &za); zcopy(za, zA); if (e[i] == 1) { Montgomery_multiplication(b, l, zm , *zA, zxp, &za); zcopy(za, zA); } #ifdef DEBUG zwriteln(*zA); #endif } zone(&zxp); Montgomery_multiplication(b, l, zm, *zA, zxp, &za); zcopy(za, zA); zfree(&za); zfree(&zb); zfree(&zxp); } int main(void) { char e[4] = {1, 1, 0, 1}; long b = 10, l = 5, t = 3; verylong zA = 0, zR = 0, za = 0, zm = 0, zx = 0; zintoz(100000l, &zR); zintoz(72639l, &zm); zintoz(5792l, &zx); Montgomery_exponentiation(e, b, l, t, zR, zm, zx, &zA); zsexpmod(zx, 11, zm, &za); zwriteln(za); zwriteln(zA); zfree(&zA); zfree(&zR); zfree(&za); zfree(&zm);

zfree(&zx); return 0; }

14.98 Algorithm Addition chain exponentiation addchain.c freelip (1,650)


/* Author: Pate Williams (c) 1997

Addition chain exponentiation. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al 14.6.2 Section pages 620 - 623. */ #include #include #include #include <assert.h> <stdio.h> <stdlib.h> "lip.h"

#define DEBUG void long_to_binary(long a, long *e, long *t) { long i; *t = z2logs(a); for (i = 0; i < *t; i++) { e[i] = a & 1; a >>= 1; } } void addition_chain(long exp, verylong zg, verylong *zge) { int found; long I[65][2], d[32], e[32], i, j, k, s, t, u[65]; verylong *zg1; long_to_binary(exp, e, &t); for (i = 0, j = t - 1; j >= 0; i++, j--) d[i] = e[j]; u[0] = 1, u[1] = 2 * d[0], u[2] = u[1] + d[1]; for (s = 3, j = 2; j < t; s += 2, j++) u[s] = 2 * u[s - 1], u[s + 1] = u[s] + d[j]; zg1 = calloc(s, sizeof(verylong)); assert(zg1 != 0); for (i = 1; i < s; i++) { found = 0; for (j = 0; !found && j < i; j++) for (k = 0; !found && k < i; k++) if (u[i] == u[j] + u[k]) found = 1, I[i][0] = j, I[i][1] = k; } #ifdef DEBUG for (i = 0; i < s; i++) printf("%ld ", u[i]); printf("\n");

for (i = 1; i < s; i++) printf("%ld %ld %ld\n", i, I[i][0], I[i][1]); #endif zcopy(zg, &zg1[0]); for (i = 1; i < s; i++) zmul(zg1[I[i][0]], zg1[I[i][1]], &zg1[i]); zcopy(zg1[s - 1], zge); free(zg1); } void main(void) { long exp = 143l; verylong za = 0, zg = 0, zge = 0; zintoz(2l, &zg); addition_chain(exp, zg, &zge); zwriteln(zge); zsexp(zg, exp, &za); zwriteln(za); zfree(&za); zfree(&zg); zfree(&zge);

14.117 Algorithm Fixed-base comb method for exponentiation fbcomb.c freelip (3,660)
/* Author: Pate Williams (c) 1997 Fixed-base comb method for exponentiation. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al 14.6.3 Section pages 623 - 627. <assert.h> <stdio.h> <stdlib.h> <time.h> "lip.h"

*/

#include #include #include #include #include

/*#define DEBUG*/ long binary_to_long(long t, long *e) { long i, value = e[t - 1]; for (i = t - 2; i >= 0; i--) value = (value << 1) + e[i]; return value; } void long_to_binary(long a, long *e, long *t) { long i;

*t = z2logs(a); for (i = 0; i < *t; i++) { e[i] = a & 1; a >>= 1; } } void fixed_base_comb(long exp, verylong zg, verylong *zA) { long **EA, *X, *Y, Ijk, a, ah, b, c, e[32], f[32]; long h, h2, i, j, k, s, t, v; verylong za = 0, zb = 0, zc = 0, **zG, *zg1; long_to_binary(exp, e, &t); t--; do h = rand() % (t + 2); while (h == 0); a = ceil((double)(t + 1) / h); h2 = pow(2, h); do v = rand() % (a + 1); while (v == 0); b = ceil((double) a / v); ah = a * h; /* create the exponent array */ EA = calloc(h, sizeof(long *)); assert(EA != 0); for (i = 0; i < h; i++) { EA[i] = calloc(a, sizeof(long)); assert(EA[i] != 0); } /* allocate other arrays */ X = calloc(ah, sizeof(long)); assert(X != 0); Y = calloc(h, sizeof(long)); assert(Y != 0); zG = calloc(v, sizeof(verylong *)); assert(zG != 0); for (j = 0; j < v; j++) { zG[j] = calloc(h2, sizeof(verylong)); assert(zG[j] != 0); } zg1 = calloc(h, sizeof(zg1)); assert(zg1 != 0); for (i = 0; i <= t; i++) X[i] = e[i]; /* create exponent array from binary representation */ i = 0; for (j = 0; j < h; j++) for (k = 0; k < a; k++) EA[j][k] = X[i++]; for (i = 0; i < h; i++) zsexp(zg, pow(2, i * a), &zg1[i]); for (i = 1; i < h2; i++) { long_to_binary(i, f, &s); zone(&za); for (j = 0; j < s; j++) { zsexp(zg1[j], f[j], &zb); zmul(zb, za, &zc); zcopy(zc, &za);

} zcopy(za, &zG[0][i]); for (j = 1; j < v; j++) zsexp(zG[0][i], pow(2, j * b), &zG[j][i]); } #ifdef DEBUG printf("a = %ld\n", a); printf("b = %ld\n", b); printf("h = %ld\n", h); printf("t = %ld\n", t + 2); printf("v = %ld\n", v); for (i = 0; i < h; i++) { for (j = 0; j < a; j++) printf("%d", EA[i][j]); printf("\n"); } printf("i g\n"); for (i = 0; i < h; i++) { printf("%ld ", i); zwriteln(zg1[i]); } printf("j i G[j][i]\n"); for (j = 0; j < v; j++) { for (i = 1; i < h2; i++) { printf("%ld %ld ", j, i); zwriteln(zG[j][i]); } } #endif zone(zA); for (k = b - 1; k >= 0; k--) { zsq(*zA, &za); zcopy(za, zA); for (j = v - 1; j >= 0; j--) { c = j * b + k; for (i = 0; i < h; i++) Y[i] = EA[i][c]; Ijk = binary_to_long(h, Y); #ifdef DEBUG printf("%ld %ld\n", j, Ijk); #endif if (Ijk != 0) { zmul(*zA, zG[j][Ijk], &za); zcopy(za, zA); } } } /* free the allocated resources */ free(X); free(Y); free(zg1); for (i = 0; i < h; i++) free(EA[i]); for (i = 0; i < v; i++) free(zG[i]); zfree(&za); zfree(&zb); zfree(&zc); }

void main(void) { long exp; verylong zA = 0, za = 0, zg = 0; srand(time(NULL)); zintoz(2l, &zg); for (exp = 50l; exp < 155l; exp++) { fixed_base_comb(exp, zg, &zA); zsexp(zg, exp, &za); /*zwriteln(zA); zwriteln(za);*/ if (zcompare(zA, za) != 0) printf("%ld error in exponent!\n", exp); } }

14.121 Algorithm Signed-digit recoding sdrec.c freelip (960)


/* Author: Pate Williams (c) 1997

Signed-digit exponent recoding. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al 14.7.1 Section pages 627 - 628. */ #include <stdio.h> #include "lip.h" #define DEBUG void long_to_binary(long a, long *e, long *t) { long i; *t = z2logs(a); for (i = 0; i < *t; i++) { e[i] = a & 1; a >>= 1; } } void signed_digit_recoding(long exp, long *d, long *t) { long c[64], e[64], i; long_to_binary(exp, e, t); #ifdef DEBUG for (i = *t - 1; i >= 0; i--) printf("%ld", e[i]); printf("\n"); #endif e[*t] = e[*t + 1] = 0; c[0] = 0; for (i = 0; i <= *t; i++) {

c[i + 1] = (e[i] + e[i + 1] + c[i]) / 2; d[i] = e[i] + c[i] - 2 * c[i + 1]; } }

int main(void) { long d[64], exp = 887l, i, t; signed_digit_recoding(exp, d, &t); for (i = t; i >= 0; i--) printf("%d", d[i]); printf("\n"); return 0; }

14.130 Algorithm Exponentiation using an SR(k) representation srk.c freelip (2,505)


/* Author: Pate Williams (c) 1997

k-ary string-replacement exponentiation. See "Handbook of Applied Cryptography" by Alfred J. Menezes et al 14.7.2 Section pages 628-629. */ #include #include #include #include <assert.h> <stdio.h> <stdlib.h> "lip.h"

#define DEBUG void long_to_binary(long a, long *e, long *t) { long i; *t = z2logs(a); for (i = 0; i < *t; i++) { e[i] = a & 1; a >>= 1; } } void k_ary_string_replacement(long exp, long k, long *f, long *t) { int found; long c, e[32], i, i2, j, l, m, n; long_to_binary(exp, e, t); #ifdef DEBUG for (i = *t - 1; i >= 0; i--) printf("%ld", e[i]);

printf("\n"); #endif for (i = k; i >= 2; i--) { i2 = pow(2, i) - 1, j = *t - 1, n = j; while (j >= 0) { if (e[j] == 1) { c = j - i + 1; if (c >= 0) { for (found = 1, l = j; found && l >= c; l--) found = e[l] == 1; if (found) { for (m = j; m > c; m--) f[m] = 0; f[c] = i2; } else for (m = j; m >= c; m--) f[m] = e[m]; j = n = c - 1; } else while (j >= 0) f[j] = e[j], j--; } else f[n--] = e[j--]; } for (j = 0; j < *t; j++) e[j] = f[j]; #ifdef DEBUG for (l = *t - 1; l >= 0; l--) printf("%ld", f[l]); printf(" SR(%ld)\n", k); #endif }

void srk_exp(long exp, long k, verylong zg, verylong *zA) { long f[32], i, j, l, t; verylong za = 0, *zg1; l = pow(2, k); zg1 = calloc(l, sizeof(verylong)); assert(zg1 != 0); k_ary_string_replacement(exp, k, f, &t); zcopy(zg, &zg1[1]); for (i = 2; i <= k; i++) { j = pow(2, i - 1) - 1; l = pow(2, i) - 1; zsq(zg1[j], &za); zmul(za, zg, &zg1[l]); } zone(zA); for (i = t - 1; i >= 0; i--) { zsq(*zA, &za); zcopy(za, zA); j = f[i]; if (j != 0) { zmul(*zA, zg1[j], &za); zcopy(za, zA);

} } free(zg1); zfree(&za); } int main(void) { long exp = 28573l, k = 3l, f[32], t; verylong zA = 0, za = 0, zg = 0; zintoz(2l, &zg); k_ary_string_replacement(exp, k, f, &t); exp = 987l; srk_exp(exp, k, zg, &zA); zsexp(zg, exp, &za); zwriteln(zA); zwriteln(za); if (zcompare(zA, za) != 0) printf("*error*\nsrk_exp failure!\n"); zfree(&zA); zfree(&za); zfree(&zg); return 0; }

You might also like