Top Banner
Chapter 01 Classical Cryptography 1.11 te0111.c (6,063) 1.1 (a) ex0101a.c (4,623) 1.1 (b) ex0101b.c (3,190) 1.1 (c) ex0101c.c (3,518) 1.1 (d) ex0101d.c (4,944) 1.3 ex0103.c (2,813) 1.4 ex0104a.c (7,231) 1.5 ex0105.c (8,887) 1.6 ex0106.c (7,709) 1.7 ex0107.c (3,002) 1.8 ex0108.c (1,169) 1.10 ex0110.c (1,031) Example 1.11 te0111.c (6,063) /* Author: Pate Williams (c) 1997 Example 1.11
188

Classical CryptoAlgorithms (Ch 01-12)

Dec 01, 2015

Download

Documents

Rudrahara

cryptography
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Classical CryptoAlgorithms (Ch 01-12)

Chapter 01 Classical Cryptography

1.11 te0111.c (6,063)

1.1 (a) ex0101a.c (4,623)

1.1 (b) ex0101b.c (3,190)

1.1 (c) ex0101c.c (3,518)

1.1 (d) ex0101d.c (4,944)

1.3 ex0103.c (2,813)

1.4 ex0104a.c (7,231)

1.5 ex0105.c (8,887)

1.6 ex0106.c (7,709)

1.7 ex0107.c (3,002)

1.8 ex0108.c (1,169)

1.10 ex0110.c (1,031)

Example

1.11 te0111.c (6,063)

/* Author: Pate Williams (c) 1997

Example 1.11 "Ciphertext obtained from a Vigenere Cipher: CHREEVOAHMAERATBIAXXWTNXBEEOPHBSBQMQEQERBW RVXUOAKXAOSXXWEAHBWGJMMQMNKGRFVGXWTRZXWAIK LXFPSKAUTEMNDCMGTSXMXBTUIADNGMGPSRELXNJELX VRVPRTULHDNQWTWDTYGBPHXTFALJHASVBFXNGLLCHR ZBWELEKMSJIKNBHWRJGNMGJSGLXFEYPHAGNRBIEQJT

Page 2: Classical CryptoAlgorithms (Ch 01-12)

AMRVLCRREMNDGLXRRIMGNSNRWCHRQHAEYEVTAQEBBI PEEWEVKAKOEWADREMXMTBHHCHRTKDNVRZCHRCLQOHP WQAIIWXNRMGWOIIFKEE" -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 33.*/

#include <ctype.h>#include <stdio.h>#include <string.h>

long gcd(long a, long b){ long r;

while (b > 0) r = a % b, a = b, b = r; return a;}

int main(void){ char cipher[15][25] = {"CHREEVOAHMAERATBIAXXWTN", "XBEEOPHBSBQMQEQERBW", "RVXUOAKXAOSXXWEAHBWGJMM", "QMNKGRFVGXWTRZXWAIK", "LXFPSKAUTEMNDCMGTSXMXBT", "UIADNGMGPSRELXNJELX", "VRVPRTULHDNQWTWDTYGBPHX", "TFALJHASVBFXNGLLCHR", "ZBWELEKMSJIKNBHWRJGNMGJ", "SGLXFEYPHAGNRBIEQJT", "AMRVLCRREMNDGLXRRIMGNSN", "RWCHRQHAEYEVTAQEBBI", "PEEWEVKAKOEWADREMXMTBHH", "CHRTKDNVRZCHRCLQOHP", "WQAIIWXNRMGWOIIFKEE"}; char answer[256], ciphert[500], ciphertext[500]; char keyword[16], word_1[4], word_2[4]; double Ic, MIc[16][16][26], sum; int found = 0; long count = 0, i, j, k, o_count = 0, occur[16]; long col, frequency[26] = {0}, key_length, m, n; long f[26], fp[26], g, l, plaintext;

/* tabulate ciphertext frequencies */ for (i = 0; i < 15; i++) for (j = 0; j < strlen(cipher[i]); j++) ciphertext[count] = ciphert[count++] = cipher[i][j]; /* perform the Kasiski test */ for (i = 0; !found && i < count - 2; i++) { word_1[0] = ciphertext[i]; word_1[1] = ciphertext[i + 1]; word_1[2] = ciphertext[i + 2]; o_count = 1; occur[0] = i; for (j = i + 3; j < count - 2; j++) {

Page 3: Classical CryptoAlgorithms (Ch 01-12)

word_2[0] = ciphertext[j]; word_2[1] = ciphertext[j + 1]; word_2[2] = ciphertext[j + 2]; if (strcmp(word_1, word_2) == 0) { occur[o_count] = j; o_count++; } } found = o_count >= 3; } key_length = gcd(occur[0], occur[1]); for (i = 2; i < o_count; i++) key_length = gcd(key_length, occur[i]); printf("total number of ciphertext characters = %ld\n", count); printf("keyword length = %ld\n", key_length); /* compute indices of coincidence */ found = 0; n = count; for (m = 2; !found && m < 15; m++) { col = n / m; i = 0; for (j = 0; j < col; j++) for (k = 0; k < m; k++) ciphertext[k * col + j] = ciphert[i++]; i = 0; for (j = 0; j < m; j++) { for (k = 0; k < 26; k++) frequency[k] = 0; for (k = 0; k < col; k++) frequency[ciphertext[i++] - 'A']++; sum = 0.0; for (k = 0; k < 26; k++) sum += frequency[k] * (frequency[k] - 1); Ic = sum / (col * (col - 1)); printf("Ic = %4.3lf\n", Ic); } printf("another value of m = %ld (n or y)? ", m); scanf("%s", answer); found = tolower(answer[0]) == 'n'; if (found) key_length = m; } printf("keyword length = %ld\n", key_length); col = count / key_length; i = 0; for (j = 0; j < col; j++) for (k = 0; k < key_length; k++) ciphertext[k * col + j] = ciphert[i++]; for (i = 0; i < key_length - 1; i++) { for (j = 0; j < 26; j++) f[j] = 0; for (j = 0; j < col; j++) f[ciphertext[i * col + j] - 'A']++; for (j = i + 1; j < key_length; j++) { for (k = 0; k < 26; k++) fp[k] = 0; for (k = 0; k < col; k++) fp[ciphertext[j * col + k] - 'A']++; sum = 0.0; for (k = 0; k < 26; k++) sum += f[k] * fp[k];

Page 4: Classical CryptoAlgorithms (Ch 01-12)

sum /= (col * col); printf("%4.3lf ", sum); } printf("\n"); } for (i = 0; i < key_length - 1; i++) { for (j = 0; j < 26; j++) f[j] = 0; for (j = 0; j < col; j++) f[ciphertext[i * col + j] - 'A']++; for (j = i + 1; j < key_length; j++) { printf("%ld %ld ", i + 1, j + 1); for (k = 0; k < 26; k++) fp[k] = 0; for (k = 0; k < col; k++) fp[ciphertext[j * col + k] - 'A']++; for (g = 0; g < 26; g++) { sum = 0.0; for (l = 0; l < 26; l++) { m = (l - g) % 26; if (m < 0) m += 26; sum += f[l] * fp[m]; } MIc[i][j][g] = sum / (col * col); printf("%4.3lf ", MIc[i][j][g]); if ((g + 1) % 9 == 0) printf("\n "); } printf("\n"); } } for (i = 0; i < key_length - 1; i++) { for (j = i + 1; j < key_length; j++) { for (g = 0; g < 26; g++) { if (MIc[i][j][g] > 0.061) printf("%ld %ld %2ld %4.3lf\n", i, j, g, MIc[i][j][g]); } } } keyword[0] = 'A'; keyword[1] = 'R'; keyword[2] = 'E'; keyword[3] = 'V'; keyword[4] = 'K'; keyword[5] = '\0'; found = 0; for (i = 0; !found && i < 26; i++) { j = 0; for (k = 0; k < count; k++) { plaintext = ciphert[k] - keyword[j++]; if (j == key_length) j = 0; if (plaintext < 0) plaintext += 26; printf("%c", plaintext + 'A'); if ((k + 1) % 25 == 0) printf("\n"); } printf("\ncorrect decryption (n or y)? "); scanf("%s", answer); found = tolower(answer[0]) == 'y'; if (!found) { for (j = 0; j < key_length; j++) {

Page 5: Classical CryptoAlgorithms (Ch 01-12)

keyword[j] -= (char) 'A'; keyword[j]++; if (keyword[j] == 26) keyword[j] -= (char) 26; keyword[j] += (char) 'A'; } } } printf("keyword = "); for (i = 0; i < key_length; i++) printf("%c", keyword[i]); printf("\n"); return 0;}

Exercises

1.1 (a) ex0101a.c (4,623)

/* Author: Pate Williams (c) 1997

Exercise 1.1 "Below are given four examples of cipehertext, one obtained from a Substitution Cipher, one from a Vigenere Cipher, one from an Affine Cipher, and one unspecified. In each case, the task is to determine the plaintext." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 40.*/

#include <ctype.h>#include <stdio.h>#include <stdlib.h>#include <string.h>

struct code {double rfreq; long alpha, count;};struct digram {double rfreq; long alpha1, alpha2, count;};

int main(void){ char cipher[11][24] = {"EMGLOSUDCGDNCUSWYSFHNSF", "CYKDPUMLWGYICOXYSIPJCK", "QPKUGKMGOLICGINCGACKSNI", "SACYKZSCKXECJCKSHYSXCG", "OIDPKZCNKSHICGIWYGKKGKG", "OLDSILKGOIUSIGLEDSPWZU", "GFZCCNDGYYSFUSZCNXEOJNC", "GYEOWEUPXEZGACGNFGLKNS", "ACIGOIYCKXCJUCIUZCFZCCN", "DGYYSFEUEKUZCSOCFZCCNC", "IACZEJNCSHFZEJZEGMXCYHC"}; char ch, ciphertext[500], lt_ch, rt_ch; char c_a, c_e, c_o, c_r, c_s, c_w;

Page 6: Classical CryptoAlgorithms (Ch 01-12)

char answer[256], plaintext[500]; long frequency[26] = {0}, count = 0, i, j, k = 0, l; long di_freq[26][26] = {{0}}, d_count = 0, line; struct code t, c[26]; struct digram *d, dt;

for (i = 0; i < 11; i++) { for (j = 0; j < strlen(cipher[i]); j++) { ch = ciphertext[count++] = cipher[i][j]; frequency[ch - 'A']++; } } for (i = 0; i < 26; i++) { c[i].alpha = i + 'A'; c[i].count = frequency[i]; } for (i = 0; i < 25; i++) for (j = i + 1; j < 26; j++) if (c[i].count < c[j].count) t = c[i], c[i] = c[j], c[j] = t; for (i = 0; i < 26; i++) { c[i].rfreq = c[i].count / (double) count; if (c[i].rfreq != 0.0) printf("%c %lf\n", c[i].alpha, c[i].rfreq); } lt_ch = ciphertext[0]; for (i = 1; i < count - 1; i++) { rt_ch = ciphertext[i]; di_freq[lt_ch - 'A'][rt_ch - 'A']++; lt_ch = rt_ch; } for (i = 0; i < 26; i++) for (j = 0; j < 26; j++) if (di_freq[i][j] != 0) d_count++; d = calloc(d_count, sizeof(struct digram)); for (i = 0; i < 26; i++) { for (j = 0; j < 26; j++) { if (di_freq[i][j] != 0) { d[k].alpha1 = i + 'A'; d[k].alpha2 = j + 'A'; d[k++].count = di_freq[i][j]; } } } for (i = 0; i < d_count - 1; i++) for (j = i + 1; j < d_count; j++) if (d[i].count < d[j].count) dt = d[i], d[i] = d[j], d[j] = dt; for (i = 0; i < d_count; i++) if (d[i].count != 0) printf("%3ld %c %c %ld\n", i, d[i].alpha1, d[i].alpha2, d[i].count); c_e = (char) c[0].alpha; c_a = (char) c[1].alpha; c_o = (char) c[2].alpha; c_r = (char) c[5].alpha; c_s = (char) c[3].alpha;

Page 7: Classical CryptoAlgorithms (Ch 01-12)

c_w = 'F'; for (i = 0; i < count; i++) { ch = ciphertext[i]; if (ch == c_a) plaintext[i] = 'A'; else if (ch == c_e) plaintext[i] = 'E'; else if (ch == c_o) plaintext[i] = 'O'; else if (ch == c_r) plaintext[i] = 'R'; else if (ch == c_s) plaintext[i] = 'S'; else if (ch == c_w) plaintext[i] = 'W'; else plaintext[i] = '-'; } line = count / 25; if (line % 25 != 0) line++; do { i = j = 0; for (k = 0; k < line; k++) { printf("P: "); for (l = 0; l < 25; l++) if (i < count) printf("%c", plaintext[i++]); printf("\nC: "); for (l = 0; l < 25; l++) if (j < count) printf("%c", ciphertext[j++]); printf("\n"); } do { printf("Command: M(ap) Q(uit) U(nmap)? "); scanf("%s", answer); ch = (char) tolower(answer[0]); } while (ch != 'm' && ch != 'q' && ch != 'u'); if (ch != 'q') { if (ch == 'm') { printf("Ciphertext character: "); scanf("%s", answer); c_a = (char) toupper(answer[0]); printf("Plaintext character: "); scanf("%s", answer); c_e = (char) toupper(answer[0]); for (i = 0; i < count; i++) if (c_a == ciphertext[i]) plaintext[i] = c_e; } if (ch == 'u') { printf("Plaintext character: "); scanf("%s", answer); c_a = (char) toupper(answer[0]); for (i = 0; i < count; i++) if (c_a == plaintext[i]) plaintext[i] = '-'; } } } while (ch != 'q'); return 0;}

Page 8: Classical CryptoAlgorithms (Ch 01-12)

1.1 (b) ex0101b.c (3,190)

/* Author: Pate Williams (c) 1997

Exercise 1.1 (b) "Below are given four examples of cipehertext, one obtained from a Substitution Cipher, one from a Vigenere Cipher, one from an Affine Cipher, and one unspecified. In each case, the task is to determine the plaintext." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 40.*/

#include <ctype.h>#include <stdio.h>#include <string.h>

long gcd(long a, long b){ long r;

while (b > 0) r = a % b, a = b, b = r; return a;}

int main(void){ char cipher[15][25] = {"KCCPKBGUFDPHQTYAVINRRTMV", "GRKDNBVFDETDGILTXRGUD", "DKOTFMBPVGEGLTGCKQRACQCW", "DNAWCRXIZAKFTLEWRPTYC", "QKYVXCHKFTPONCQQRHJVAJUW", "ETMCMSPKQDYHJVDAHCTRL", "SVSKCGCZQQDZXGSFRLSWCWSJ", "TBHAFSIASPRJAHKJRJUMV", "GKMITZHFPDISPZLVLGWTFPLK", "KEBDPGCEBSHCTJRWXBAFS", "PEZQNRWXCVYCGAONWDDKACKA", "WBBIKFTIOVKCGGHJVLNHI", "FFSQESVYCLACNVRWBBIREPBB", "VFEXOSCDYGZWPFDTKFQIY", "CWHJVLNHIQIBTKHJVNPIST"}; char ciphertext[500], plaintext[500]; char keyword[16], known[] = "ILEARNEDHOWTO"; char word_1[4], word_2[4]; int found = 0; long count = 0, i, j, o_count, occur[50]; long distance[50], key_length;

for (i = 0; i < 15; i++) for (j = 0; j < strlen(cipher[i]); j++) ciphertext[count++] = cipher[i][j];

Page 9: Classical CryptoAlgorithms (Ch 01-12)

/* perform the Kasiski test */ for (i = 0; !found && i < count - 2; i++) { word_1[0] = ciphertext[i]; word_1[1] = ciphertext[i + 1]; word_1[2] = ciphertext[i + 2]; word_1[3] = '\0'; occur[0] = i; o_count = 1; for (j = i + 3; j < count - 2; j++) { word_2[0] = ciphertext[j]; word_2[1] = ciphertext[j + 1]; word_2[2] = ciphertext[j + 2]; word_2[3] = '\0'; if (strcmp(word_1, word_2) == 0) occur[o_count++] = j; } found = o_count > 3; } for (i = 0; i < o_count - 1; i++) distance[i] = occur[i + 1] - occur[i]; key_length = gcd(distance[0], distance[1]); for (i = 2; i < o_count - 1; i++) key_length = gcd(key_length, distance[i]); printf("keyword length = %ld\n", key_length); for (i = 0; i < key_length; i++) { keyword[i] = (char) (ciphertext[i] - known[i]); if (keyword[i] < 0) keyword[i] += (char) 26; keyword[i] += (char) 'A'; } keyword[key_length] = '\0'; printf("keyword = %s\n", keyword); for (i = 0; i < count - key_length; i += key_length) { for (j = 0; j < key_length; j++) { plaintext[i + j] = (char) (ciphertext[i + j] - keyword[j]); if (plaintext[i + j] < 0) plaintext[i + j] += (char) 26; plaintext[i + j] += (char) 'A'; } } for (i = 0; i < count - key_length; i++) { printf("%c", plaintext[i]); if ((i + 1) % 25 == 0) printf("\n"); } printf("\n"); return 0;}

1.1 (c) ex0101c.c (3,518)

/* Author: Pate Williams (c) 1997

Exercise 1.1 (c) "Below are given four examples of cipehertext, one obtained from a Substitution Cipher, one from a Vigenere Cipher, one from an Affine Cipher, and one unspecified. In each case, the

Page 10: Classical CryptoAlgorithms (Ch 01-12)

task is to determine the plaintext." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 40.*/

#include <ctype.h>#include <stdio.h>#include <string.h>

struct code {long alpha, count;};

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

long gcd(long a, long b){ long r;

while (b > 0) r = a % b, a = b, b = r; return a;}

int main(void){ char cipher[9][25] = {"KQEREJEBCPPCJCRKIEACUZ", "BKRVPKRBCIBQCARBJCVFCUP", "KRIOFKPACUZQEPBKRXPEII", "EABDKPBCPFCDCCAFIEABDKP", "BCPFEQPKAZBKRHAIBKAPCC", "IBURCCDKDCCJCIDFUIXPAFF", "ERBICZDFKABICBBENEFCUP", "JCVKABPCYDCCDPKBCOCPERK", "IVKSCPICBRKIJPKABI"}; char answer[256], ciphertext[500]; long a[2][2], iv[2][2], b[2], det, x[2]; long count = 0, i, j; long frequency[26] = {0};

Page 11: Classical CryptoAlgorithms (Ch 01-12)

struct code c[26], temp;

for (i = 0; i < 9; i++) { for (j = 0; j < strlen(cipher[i]); j++) { ciphertext[count] = cipher[i][j]; frequency[ciphertext[count] - 'A']++; count++; } } for (i = 0; i < 26; i++) { c[i].alpha = i + 'A'; c[i].count = frequency[i]; } /* sort the code array into descending order */ for (i = 0; i < 25; i++) for (j = i + 1; j < 26; j++) if (c[i].count < c[j].count) temp = c[i], c[i] = c[j], c[j] = temp; for (i = 0; i < 26; i++) if (c[i].count != 0) printf("%c %ld\n", c[i].alpha, c[i].count); do { printf("guess for second most frequently"); printf(" occurring character %c = ", c[1].alpha); scanf("%s", answer); a[0][0] = 'E' - 'A'; a[0][1] = 1; a[1][0] = toupper(answer[0]) - 'A'; a[1][1] = 1; b[0] = c[0].alpha - 'A'; b[1] = c[1].alpha - 'A'; iv[0][0] = a[1][1]; iv[0][1] = - a[0][1]; iv[1][0] = - a[1][0]; iv[1][1] = a[0][0]; det = (a[0][0] * a[1][1] - a[0][1] * a[1][0]) % 26; if (det < 0) det += 26; det = Extended_Euclidean(det, 26); x[0] = (det * (iv[0][0] * b[0] + iv[0][1] * b[1])) % 26; x[1] = (det * (iv[1][0] * b[0] + iv[1][1] * b[1])) % 26; if (x[0] < 0) x[0] += 26; if (x[1] < 0) x[1] += 26; printf("a = %ld\n", x[0]); printf("b = %ld\n", x[1]); printf("gcd(a, 26) = %ld\n", gcd(x[0], 26)); if (x[0] != 0) { x[1] += 'A'; det = Extended_Euclidean(x[0], 26); for (i = 0; i < count; i++) { b[0] = (det * (ciphertext[i] - x[1])) % 26; if (b[0] < 0) b[0] += 26; b[0] += 'A'; printf("%c", b[0]); if ((i + 1) % 25 == 0) printf("\n"); } } printf("\nanother guess (n or y)? ");

Page 12: Classical CryptoAlgorithms (Ch 01-12)

scanf("%s", answer); } while (tolower(answer[0]) == 'y'); return 0;}

1.1 (d) ex0101d.c (4,944)

/* Author: Pate Williams (c) 1997

Exercise 1.1 (d) "Below are given four examples of cipehertext, one obtained from a Substitution Cipher, one from a Vigenere Cipher, one from an Affine Cipher, and one unspecified. In each case, the task is to determine the plaintext." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson pages 40 - 41.*/

#include <ctype.h>#include <stdio.h>#include <string.h>

struct code {long alpha, count;};

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

long gcd(long a, long b){ long r;

while (b > 0) r = a % b, a = b, b = r; return a;}

Page 13: Classical CryptoAlgorithms (Ch 01-12)

int main (void){ char cipher[17][26] = {"BNVSNSIHQCEELSSKKYERIFJKX", "UMBGYKAMQLJTYAVFBKVT", "DVBPVVRJYYLAOKYMPQSCGDLFS", "RLLPROYGESEBUUALRWXM", "MASAZLGLEDFJBZAVVPXWICGJX", "ASCBYEHOSNMULKCEAHTQ", "OKMFLEBKFXLRRFDTZXCIWBJSI", "CBGAWDVYDHAVFJXZIBKC", "GJIWEAHTTOEWTUHKRQVVRGZBX", "YIREMMASCSPBNLHJMBLR", "FFJELHWEYLWISTFVVYFJCMHYU", "YRUFSFMGESIGRLWALSWM", "NUHSIMYYITCCQPZSICEHBCCMZ", "FEGVJYOCDEMMPGHVAAUM", "HYGGCKTMBLRX"}; char ciphertext[500], plaintext[500]; char keyword[16], known[] = "IGREWUPAMONGSLOW"; char word_1[4], word_2[4]; int found = 0; long count = 0, frequency[26] = {0}, i, j; long distance[16], o_count = 0, occur[16]; long key_length; struct code c[26], temp;

/* tabulate character frequencies */ for (i = 0; i < 17; i++) { for (j = 0; j < strlen(cipher[i]); j++) { ciphertext[count] = cipher[i][j]; frequency[ciphertext[i] - 'A']++; count++; } } for (i = 0; i < 26; i++) { c[i].alpha = i + 'A'; c[i].count = frequency[i]; } /* sort the code array into descending order */ for (i = 0; i < 25; i++) for (j = i + 1; j < 26; j++) if (c[i].count < c[j].count) temp = c[i], c[i] = c[j], c[j] = temp; for (i = 0; i < 26; i++) if (c[i].count != 0) printf("%c %ld\n", c[i].alpha, c[i].count); /* perform the Kasiski test */ for (i = 0; !found && i < count - 2; i++) { word_1[0] = ciphertext[i]; word_1[1] = ciphertext[i + 1]; word_1[2] = ciphertext[i + 2]; word_1[3] = '\0'; occur[0] = i; o_count = 1; for (j = i + 3; j < count - 2; j++) { word_2[0] = ciphertext[j];

Page 14: Classical CryptoAlgorithms (Ch 01-12)

word_2[1] = ciphertext[j + 1]; word_2[2] = ciphertext[j + 2]; word_2[3] = '\0'; if (strcmp(word_1, word_2) == 0) occur[o_count++] = j; } found = o_count > 3; } if (found) { for (i = 0; i < o_count - 1; i++) distance[i] = occur[i + 1] - occur[i]; key_length = gcd(distance[0], distance[1]); for (i = 2; i < o_count - 1; i++) key_length = gcd(key_length, distance[i]); } else { double IC, sum; char answer[256]; long col, k, m, n; found = 0; n = count; for (m = 1; !found && m < 15; m++) { col = n / m; i = 0; for (j = 0; j < m; j++) { for (k = 0; k < 26; k++) frequency[k] = 0; for (k = 0; k < col; k++) frequency[ciphertext[i++] - 'A']++; sum = 0.0; for (k = 0; k < 26; k++) sum += frequency[k] * (frequency[k] - 1); IC = sum / (col * (col - 1)); printf("Ic = %lf\n", IC); } printf("another value of m = %ld (n or y)? ", m); scanf("%s", answer); found = tolower(answer[0]) == 'n'; if (found) key_length = m; } } printf("keyword length = %ld\n", key_length); for (i = 0; i < key_length; i++) { keyword[i] = (char) (ciphertext[i] - known[i]); if (keyword[i] < 0) keyword[i] += (char) 26; keyword[i] += (char) 'A'; } keyword[key_length] = '\0'; printf("keyword = %s\n", keyword); for (i = 0; i < count - key_length; i += key_length) { for (j = 0; j < key_length; j++) { plaintext[i + j] = (char) (ciphertext[i + j] - keyword[j]); if (plaintext[i + j] < 0) plaintext[i + j] += (char) 26; plaintext[i + j] += (char) 'A'; } } for (i = 0; i < count - key_length; i++) { printf("%c", plaintext[i]);

Page 15: Classical CryptoAlgorithms (Ch 01-12)

if ((i + 1) % 25 == 0) printf("\n"); } printf("\n"); return 0;}

1.3 ex0103.c (2,813)

/*Author: James Pate Williams (c) 2001

Exercise 1.3 from _Cryprography Theory and Practice_by Douglas R. Stinson p. 41. Originally, I had thisproblem incorrect. Martin Manscher of the TechnicalUniversity of Denmark suggested the followingsolution.

*/

#include <math.h>#include <stdio.h>

void extendedEuclid(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;

extendedEuclid(a, n, &x, &y, &d);if (d == 1)

return x;return 0;

}

int main(void) {int As11, As12, As21, As22, Asqr, detA, i, j, k, l, n = 26;int count1 = 0, count2 = 0, count3 = 0, count4 = 0;int count5 = 0, count6 = 0, count7 = 0, count8 = 0;long a11, m = 26;

Page 16: Classical CryptoAlgorithms (Ch 01-12)

/* A = | i j | | k l |

det(A) = (i * l - j * k) mod 26

We want to find A such that det(A) = -+ 1 and A * A = 1*/for (i = 0; i < n; i++) {

for (j = 0; j < n; j++) {for (k = 0; k < n; k++) {

for (l = 0; l < n; l++) {detA = (i * l - j * k) % n;if (detA < 0)

detA += 26;As11 = (i * i + j * k) % n;As12 = (i * j + j * l) % n;As21 = (k * i + l * k) % n;As22 = (k * j + l * l) % n;Asqr = As11 == 1 && As12 == 0 && As21

== 0 && As22 == 1;if (Asqr) {

count1++;if (detA == n - 1) {

count2++;a11 = (1 - i * i) % m;if (a11 < 0)

a11 += m;if (inverse(a11, m) !=

0)count3++;

else if (a11 == 0)count4++;

else if (a11 == 13)count5++;

else if (a11 % 2 == 0)count6++;

}else if (detA == 1)

count7++;}else

count8++;}

}}

}printf("number of involutary matrices with det(A) = + 1: %3d\n",

count7);printf("number of involutary matrices with det(A) = - 1: %3d\n",

count2);printf("det(A) = - 1, (1 - a[1][1] ^ 2) %% 26 in Z_26 : %3d\n",

count3);printf("det(A) = - 1, (1 - a[1][1] ^ 2) %% 26 = 0 : %3d\n",

count4);printf("det(A) = - 1, (1 - a[1][1] ^ 2) %% 26 = 13 : %3d\n",

count5);

Page 17: Classical CryptoAlgorithms (Ch 01-12)

printf("det(A) = - 1, (1 - a[1][1] ^ 2) %% 26 even : %3d\n", count6);

printf("total number of involutary matrices : %3d\n", count1);

printf("total number of matrices tested : %3d\n", count1 + count8);

printf("26 ** 4 = 26 ^ 4 = %f\n", pow(n, 4));return 0;

}

1.4 ex0104a.c (7,231)

/* Author: Pate Williams (c) 1997

Exercise 1.4 "Suppose we are told that the plaintext conversation yields the ciphertext hiarrtnuytus where the Hill Cipher is used (but m is not specified). Determine the encryption matrix." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 41. This is for m = 2, I had to change the ciphertext to "YUDOALQSRHYB".*/

#include <stdio.h>#include <stdlib.h>#include <string.h>

long **create_square_matrix(long n){ long i, **matrix = calloc(n, sizeof(long *));

if (!matrix) { fprintf(stderr, "fatal error\ninsufficient memory\n"); fprintf(stderr, "from create_matrix\n"); exit(1); } for (i = 0; i < n; i++) { matrix[i] = calloc(n, sizeof(long)); if (!matrix[i]) { fprintf(stderr, "fatal error\ninsufficient memory\n"); fprintf(stderr, "from create_matrix\n"); exit(1); } } return matrix;}

void delete_square_matrix(long n, long **matrix){ long i;

Page 18: Classical CryptoAlgorithms (Ch 01-12)

for (i = 0; i < n; i++) free(matrix[i]); free(matrix);}

void Euclid_extended(long a, long b, long *u, long *v, long *d){ long q, t1, t3, v1, v3;

*u = 1, *d = a; if (b == 0) { *v = 0; return; } v1 = 0, v3 = b; #ifdef DEBUG printf("----------------------------------\n"); printf(" q t3 *u *d t1 v1 v3\n"); printf("----------------------------------\n"); #endif while (v3 != 0) { q = *d / v3; t3 = *d - q * v3; t1 = *u - q * v1; *u = v1, *d = v3; #ifdef DEBUG printf("%4ld %4ld %4ld ", q, t3, *u); printf("%4ld %4ld %4ld %4ld\n", *d, t1, v1, v3); #endif v1 = t1, v3 = t3; } *v = (*d - a * *u) / b; #ifdef DEBUG printf("----------------------------------\n"); #endif}

long inv(long number, long modulus){ long d, u, v;

Euclid_extended(number, modulus, &u, &v, &d); if (d == 1) return u; return 0;}

void gaussian_elimination(long n, long p, long *b, long *x, long **m){ int found; long *d = calloc(n, sizeof(long)), ck, dj; long i, j, k, l, sum, t;

if (!d) { fprintf(stderr, "fatal error\ninsufficient memory\n"); fprintf(stderr, "from gaussian_elimination\n");

Page 19: Classical CryptoAlgorithms (Ch 01-12)

exit(1); } for (j = 0; j < n; j++) { found = 0, i = j; while (!found && i < n) { found = m[i][j] != 0 && inv(m[i][j], p) != 0; if (!found) i++; } if (!found) { fprintf(stderr, "fatal error\nnon-invertible matrix\n"); fprintf(stderr, "from gaussian_elimination\n"); fprintf(stderr, "j = %ld\n", j); for (k = 0; k < n; k++) { for (l = 0; l < n; l++) printf("%2ld ", m[k][l]); printf("\n"); } exit(1); } if (i > j) { /* swap elements */ for (l = j; l < n; l++) t = m[i][l], m[i][l] = m[j][l], m[j][l] = t; t = b[i], b[i] = b[j], b[j] = t; } dj = d[j] = inv(m[j][j], p); if (dj == 0) { fprintf(stderr, "fatal error\nnon-invertible element\n"); fprintf(stderr, "from gaussian elimination\n"); fprintf(stderr, "element %ld mod %ld\n", m[j][j], p); exit(1); } for (k = j + 1; k < n; k++) { ck = (dj * m[k][j]) % p; for (l = j + 1; l < n; l++) { m[k][l] = (m[k][l] - ck * m[j][l]) % p; if (m[k][l] < 0) m[k][l] += p; } b[k] = (b[k] - ck * b[j]) % p; if (b[k] < 0) b[k] += p; } } for (i = n - 1; i >= 0; i--) { sum = 0; for (j = i + 1; j < n; j++) sum += (m[i][j] * x[j]) % p; if (sum < 0) sum += p; x[i] = (d[i] * (b[i] - sum)) % p; if (x[i] < 0) x[i] += p; }}

void inverse(long n, long p, long **m, long **X){ int found; long d, i, j, k, l, sum, temp; long **B = create_square_matrix(n);

Page 20: Classical CryptoAlgorithms (Ch 01-12)

long *c = calloc(n, sizeof(long));

if (!c) { fprintf(stderr, "fatal error\ninsufficient memory\n"); fprintf(stderr, "from inverse\n"); exit(1); } for (i = 0; i < n; i++) B[i][i] = 1; for (j = 0; j < n; j++) { found = 0; for (i = j; i < n && !found;) { found = m[i][j] != 0 && inv(m[i][j], p) != 0; if (!found) i++; } if (!found) { fprintf(stderr, "fatal error\nnon-invertible matrix\n"); fprintf(stderr, "from inverse\n", j); exit(1); } if (i > j) { for (l = j; l < n; l++) { temp = m[i][l]; m[i][l] = m[j][l]; m[j][l] = temp; } for (l = 0; l < n; l++) { temp = B[i][l]; B[i][l] = B[j][l]; B[j][l] = temp; } } d = inv(m[j][j], p); for (k = j + 1; k < n; k++) c[k] = (d * m[k][j]) % p; for (k = j + 1; k < n; k++) { for (l = j + 1; l < n; l++) { m[k][l] -= (c[k] * m[j][l]) % p; m[k][l] %= p; if (m[k][l] < 0) m[k][l] += p; } } for (k = j + 1; k < n; k++) { for (l = 0; l < n; l++) { B[k][l] -= (c[k] * B[j][l]) % p; B[k][l] %= p; if (B[k][l] < 0) B[k][l] += p; } } } for (i = n - 1; i >= 0; i--) { for (j = 0; j < n; j++) { sum = 0; for (k = i + 1; k < n; k++) sum += m[i][k] * X[k][j]; X[i][j] = inv(m[i][i], p) * (B[i][j] - sum); X[i][j] %= p; if (X[i][j] < 0) X[i][j] += p; }

Page 21: Classical CryptoAlgorithms (Ch 01-12)

} delete_square_matrix(n, B); free(c);}

int main(void){ char ciphertext[16] = "YUDOALQSRHYB"; char plaintext[16] = "CONVERSATION"; long i, j, n = 4, p = 26, b[4], x[4]; long length = strlen(plaintext); long **K = create_square_matrix(n); long **k = create_square_matrix(n);

printf("plaintext: %s\n", plaintext); printf("ciphertext: %s\n", ciphertext); for (i = 0; i < length; i++) { plaintext[i] -= (char) 'A'; ciphertext[i] -= (char) 'A'; } K[0][0] = plaintext[4]; K[0][2] = plaintext[5]; K[1][1] = plaintext[4]; K[1][3] = plaintext[5]; K[2][0] = plaintext[8]; K[2][2] = plaintext[9]; K[3][1] = plaintext[8]; K[3][3] = plaintext[9]; b[0] = ciphertext[4]; b[1] = ciphertext[5]; b[2] = ciphertext[8]; b[3] = ciphertext[9]; gaussian_elimination(n, p, b, x, K); K[0][0] = x[0]; K[0][1] = x[1]; K[1][0] = x[2]; K[1][1] = x[3]; printf("the key matrix is:\n"); for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) printf("%2ld ", K[i][j]); printf("\n"); } for (i = 0; i < length / 2; i++) { b[0] = K[0][0] * plaintext[2 * i] + K[1][0] * plaintext[2 * i + 1]; b[1] = K[0][1] * plaintext[2 * i] + K[1][1] * plaintext[2 * i + 1]; b[0] = b[0] % p; b[1] = b[1] % p; if (b[0] != ciphertext[2 * i] || b[1] != ciphertext[2 * i + 1]) printf("i = %ld no solution for m = 2\n", i); } inverse(2, p, K, k); printf("the inverse key matrix is:\n"); for (i = 0; i < 2; i++) {

Page 22: Classical CryptoAlgorithms (Ch 01-12)

for (j = 0; j < 2; j++) printf("%2ld ", k[i][j]); printf("\n"); } delete_square_matrix(n, k); delete_square_matrix(n, K); return 0;}

1.5 ex0105.c (8,887)

/* Author: Pate Williams (c) 1997

Exercise 1.5 "An Affine-Hill Cipher is the following modification of the Hill Cipher...Suppose Oscar has learned that the plaintext adisplayedequation is encrypted to give the ciphertext DSRMSIOPLXLJBZULLM and Oscar also knows m = 3. Compute the key." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 42.*/

#include <stdio.h>#include <stdlib.h>#include <string.h>

long **create_square_matrix(long n){ long i, **matrix = calloc(n, sizeof(long *));

if (!matrix) { fprintf(stderr, "fatal error\ninsufficient memory\n"); fprintf(stderr, "from create_matrix\n"); exit(1); } for (i = 0; i < n; i++) { matrix[i] = calloc(n, sizeof(long)); if (!matrix[i]) { fprintf(stderr, "fatal error\ninsufficient memory\n"); fprintf(stderr, "from create_matrix\n"); exit(1); } } return matrix;}

void delete_square_matrix(long n, long **matrix){ long i;

for (i = 0; i < n; i++) free(matrix[i]);

Page 23: Classical CryptoAlgorithms (Ch 01-12)

free(matrix);}

void Euclid_extended(long a, long b, long *u, long *v, long *d){ long q, t1, t3, v1, v3;

*u = 1, *d = a; if (b == 0) { *v = 0; return; } v1 = 0, v3 = b; #ifdef DEBUG printf("----------------------------------\n"); printf(" q t3 *u *d t1 v1 v3\n"); printf("----------------------------------\n"); #endif while (v3 != 0) { q = *d / v3; t3 = *d - q * v3; t1 = *u - q * v1; *u = v1, *d = v3; #ifdef DEBUG printf("%4ld %4ld %4ld ", q, t3, *u); printf("%4ld %4ld %4ld %4ld\n", *d, t1, v1, v3); #endif v1 = t1, v3 = t3; } *v = (*d - a * *u) / b; #ifdef DEBUG printf("----------------------------------\n"); #endif}

long inv(long number, long modulus){ long d, u, v;

Euclid_extended(number, modulus, &u, &v, &d); if (d == 1) return u; return 0;}

void gaussian_elimination(long n, long p, long *b, long *x, long **m){ int found; long *d = calloc(n, sizeof(long)), ck, dj; long i, j, k, l, sum, t;

if (!d) { fprintf(stderr, "fatal error\ninsufficient memory\n"); fprintf(stderr, "from gaussian_elimination\n"); exit(1);

Page 24: Classical CryptoAlgorithms (Ch 01-12)

} for (j = 0; j < n; j++) { found = 0, i = j; while (!found && i < n) { found = m[i][j] != 0 && inv(m[i][j], p) != 0; if (!found) i++; } if (!found) { fprintf(stderr, "fatal error\nnon-invertible matrix\n"); fprintf(stderr, "from gaussian_elimination\n"); fprintf(stderr, "j = %ld\n", j); for (k = 0; k < n; k++) { for (l = 0; l < n; l++) printf("%2ld ", m[k][l]); printf("\n"); } exit(1); } if (i > j) { /* swap elements */ for (l = j; l < n; l++) t = m[i][l], m[i][l] = m[j][l], m[j][l] = t; t = b[i], b[i] = b[j], b[j] = t; } dj = d[j] = inv(m[j][j], p); if (dj == 0) { fprintf(stderr, "fatal error\nnon-invertible element\n"); fprintf(stderr, "from gaussian elimination\n"); fprintf(stderr, "element %ld mod %ld\n", m[j][j], p); exit(1); } for (k = j + 1; k < n; k++) { ck = (dj * m[k][j]) % p; for (l = j + 1; l < n; l++) { m[k][l] = (m[k][l] - ck * m[j][l]) % p; if (m[k][l] < 0) m[k][l] += p; } b[k] = (b[k] - ck * b[j]) % p; if (b[k] < 0) b[k] += p; } } for (i = n - 1; i >= 0; i--) { sum = 0; for (j = i + 1; j < n; j++) sum += (m[i][j] * x[j]) % p; if (sum < 0) sum += p; x[i] = (d[i] * (b[i] - sum)) % p; if (x[i] < 0) x[i] += p; }}

void inverse(long n, long p, long **m, long **X){ int found; long d, i, j, k, l, sum, temp; long **B = create_square_matrix(n); long *c = calloc(n, sizeof(long));

Page 25: Classical CryptoAlgorithms (Ch 01-12)

if (!c) { fprintf(stderr, "fatal error\ninsufficient memory\n"); fprintf(stderr, "from inverse\n"); exit(1); } for (i = 0; i < n; i++) B[i][i] = 1; for (j = 0; j < n; j++) { found = 0; for (i = j; i < n && !found;) { found = m[i][j] != 0 && inv(m[i][j], p) != 0; if (!found) i++; } if (!found) { fprintf(stderr, "fatal error\nnon-invertible matrix\n"); fprintf(stderr, "from inverse\n", j); exit(1); } if (i > j) { for (l = j; l < n; l++) { temp = m[i][l]; m[i][l] = m[j][l]; m[j][l] = temp; } for (l = 0; l < n; l++) { temp = B[i][l]; B[i][l] = B[j][l]; B[j][l] = temp; } } d = inv(m[j][j], p); for (k = j + 1; k < n; k++) c[k] = (d * m[k][j]) % p; for (k = j + 1; k < n; k++) { for (l = j + 1; l < n; l++) { m[k][l] -= (c[k] * m[j][l]) % p; m[k][l] %= p; if (m[k][l] < 0) m[k][l] += p; } } for (k = j + 1; k < n; k++) { for (l = 0; l < n; l++) { B[k][l] -= (c[k] * B[j][l]) % p; B[k][l] %= p; if (B[k][l] < 0) B[k][l] += p; } } } for (i = n - 1; i >= 0; i--) { for (j = 0; j < n; j++) { sum = 0; for (k = i + 1; k < n; k++) sum += m[i][k] * X[k][j]; X[i][j] = inv(m[i][i], p) * (B[i][j] - sum); X[i][j] %= p; if (X[i][j] < 0) X[i][j] += p; } }

Page 26: Classical CryptoAlgorithms (Ch 01-12)

delete_square_matrix(n, B); free(c);}

int main(void){ char ciphertext[32] = "DSRMSIOPLXLJBZULLM"; char plaintext[32] = "ADISPLAYEDEQUATION"; long i, j, l = 0, n = 12, p = 26, b[12], x[12]; long length = strlen(plaintext); long **K = create_square_matrix(n); long **k = create_square_matrix(n);

printf("plaintext: %s\n", plaintext); printf("ciphertext: %s\n", ciphertext); for (i = 0; i < length; i++) { ciphertext[i] -= (char) 'A'; plaintext[i] -= (char) 'A'; } K[0][0] = plaintext[0]; K[0][3] = plaintext[1]; K[0][6] = plaintext[2]; K[0][9] = 1; K[1][1] = plaintext[0]; K[1][4] = plaintext[1]; K[1][7] = plaintext[2]; K[1][10] = 1; K[2][2] = plaintext[0]; K[2][5] = plaintext[1]; K[2][8] = plaintext[2]; K[2][11] = 1; K[3][0] = plaintext[6]; K[3][3] = plaintext[7]; K[3][6] = plaintext[8]; K[3][9] = 1; K[4][1] = plaintext[6]; K[4][4] = plaintext[7]; K[4][7] = plaintext[8]; K[4][10] = 1; K[5][2] = plaintext[6]; K[5][5] = plaintext[7]; K[5][8] = plaintext[8]; K[5][11] = 1; K[6][0] = plaintext[9]; K[6][3] = plaintext[10]; K[6][6] = plaintext[11]; K[6][9] = 1; K[7][1] = plaintext[9]; K[7][4] = plaintext[10]; K[7][7] = plaintext[11]; K[7][10] = 1; K[8][2] = plaintext[9]; K[8][5] = plaintext[10]; K[8][8] = plaintext[11]; K[8][11] = 1; K[9][0] = plaintext[15]; K[9][3] = plaintext[16];

Page 27: Classical CryptoAlgorithms (Ch 01-12)

K[9][6] = plaintext[17]; K[9][9] = 1; K[10][1] = plaintext[15]; K[10][4] = plaintext[16]; K[10][7] = plaintext[17]; K[10][10] = 1; K[11][2] = plaintext[15]; K[11][5] = plaintext[16]; K[11][8] = plaintext[17]; K[11][11] = 1; b[0] = ciphertext[0]; b[1] = ciphertext[1]; b[2] = ciphertext[2]; b[3] = ciphertext[6]; b[4] = ciphertext[7]; b[5] = ciphertext[8]; b[6] = ciphertext[9]; b[7] = ciphertext[10]; b[8] = ciphertext[11]; b[9] = ciphertext[15]; b[10] = ciphertext[16]; b[11] = ciphertext[17]; gaussian_elimination(n, p, b, x, K); for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) K[i][j] = x[l++]; for (i = 0; i < 3; i++) b[i] = x[9 + i]; printf("the key matrix is:\n"); for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) printf("%2ld ", K[i][j]); printf("\n"); } printf("the b vector is:\n"); for (i = 0; i < 3; i++) printf("%2ld\n", b[i]); for (i = 0; i < length / 3; i++) { x[0] = K[0][0] * plaintext[3 * i] + K[1][0] * plaintext[3 * i + 1] + K[2][0] * plaintext[3 * i + 2] + b[0]; x[1] = K[0][1] * plaintext[3 * i] + K[1][1] * plaintext[3 * i + 1] + K[2][1] * plaintext[3 * i + 2] + b[1]; x[2] = K[0][2] * plaintext[3 * i] + K[1][2] * plaintext[3 * i + 1] + K[2][2] * plaintext[3 * i + 2] + b[2]; x[0] %= p; x[1] %= p; x[2] %= p; if (x[0] != ciphertext[3 * i] || x[1] != ciphertext[3 * i + 1] || x[2] != ciphertext[3 * i + 2]) printf("i = %ld no solution for m = 3\n", i);

Page 28: Classical CryptoAlgorithms (Ch 01-12)

} inverse(3, p, K, k); printf("the inverse key matrix is:\n"); for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) printf("%2ld ", k[i][j]); printf("\n"); } delete_square_matrix(n, k); delete_square_matrix(n, K); return 0;}

1.6 ex0106.c (7,709)

/* Author: Pate Williams (c) 1997

Exercise 1.6 "Here is how we might cryptanalyze the Hill Cipher using a ciphertext-only attack. Suppose we know that m = 2. Break the ciphertext into blocks of length two letters (digrams). Each such digram is the encryption of a plaintext digram using the unknown encryption matrix. Pick out the most frequent ciphertext digram and assume it is the encryption of a common digram in the list follow- ing Table 1.1 (for example TH or ST). For each such guess, proceed as in the known-plaintext attack, until the correct encryption matrix is found. Here is a sample of ciphertext for you to decrypt using this method: LMQETXYEAGTXCTUIEWNCTXLZEWUAISPZYVAPEWLMGQWYA XFTCJMSQCADAGTXLMDXNXSNPJQSYVAPRIQSMHNOCVAXFV" -Douglas R. Stinson- See "Cryptography: Theory and Practice by Douglas R. Stinson page 42.*/

#include <stdio.h>#include <stdlib.h>#include <string.h>

struct digram {long alpha1, alpha2, count;};

long **create_square_matrix(long n){ long i, **matrix = calloc(n, sizeof(long *));

if (!matrix) { fprintf(stderr, "fatal error\ninsufficient memory\n"); fprintf(stderr, "from create_matrix\n"); exit(1); } for (i = 0; i < n; i++) { matrix[i] = calloc(n, sizeof(long));

Page 29: Classical CryptoAlgorithms (Ch 01-12)

if (!matrix[i]) { fprintf(stderr, "fatal error\ninsufficient memory\n"); fprintf(stderr, "from create_matrix\n"); exit(1); } } return matrix;}

void delete_square_matrix(long n, long **matrix){ long i;

for (i = 0; i < n; i++) free(matrix[i]); free(matrix);}

void Euclid_extended(long a, long b, long *u, long *v, long *d){ long q, t1, t3, v1, v3;

*u = 1, *d = a; if (b == 0) { *v = 0; return; } v1 = 0, v3 = b; #ifdef DEBUG printf("----------------------------------\n"); printf(" q t3 *u *d t1 v1 v3\n"); printf("----------------------------------\n"); #endif while (v3 != 0) { q = *d / v3; t3 = *d - q * v3; t1 = *u - q * v1; *u = v1, *d = v3; #ifdef DEBUG printf("%4ld %4ld %4ld ", q, t3, *u); printf("%4ld %4ld %4ld %4ld\n", *d, t1, v1, v3); #endif v1 = t1, v3 = t3; } *v = (*d - a * *u) / b; #ifdef DEBUG printf("----------------------------------\n"); #endif}

long inv(long number, long modulus){ long d, u, v;

Euclid_extended(number, modulus, &u, &v, &d); if (d == 1) return u; return 0;

Page 30: Classical CryptoAlgorithms (Ch 01-12)

}

void gaussian_elimination(long n, long p, long *b, long *x, long **m){ int found; long *d = calloc(n, sizeof(long)), ck, dj; long i, j, k, l, sum, t;

if (!d) { fprintf(stderr, "fatal error\ninsufficient memory\n"); fprintf(stderr, "from gaussian_elimination\n"); exit(1); } for (j = 0; j < n; j++) { found = 0, i = j; while (!found && i < n) { found = m[i][j] != 0 && inv(m[i][j], p) != 0; if (!found) i++; } if (!found) { fprintf(stderr, "fatal error\nnon-invertible matrix\n"); fprintf(stderr, "from gaussian_elimination\n"); fprintf(stderr, "j = %ld\n", j); for (k = 0; k < n; k++) { for (l = 0; l < n; l++) printf("%2ld ", m[k][l]); printf("\n"); } exit(1); } if (i > j) { /* swap elements */ for (l = j; l < n; l++) t = m[i][l], m[i][l] = m[j][l], m[j][l] = t; t = b[i], b[i] = b[j], b[j] = t; } dj = d[j] = inv(m[j][j], p); if (dj == 0) { fprintf(stderr, "fatal error\nnon-invertible element\n"); fprintf(stderr, "from gaussian elimination\n"); fprintf(stderr, "element %ld mod %ld\n", m[j][j], p); exit(1); } for (k = j + 1; k < n; k++) { ck = (dj * m[k][j]) % p; for (l = j + 1; l < n; l++) { m[k][l] = (m[k][l] - ck * m[j][l]) % p; if (m[k][l] < 0) m[k][l] += p; } b[k] = (b[k] - ck * b[j]) % p; if (b[k] < 0) b[k] += p; } } for (i = n - 1; i >= 0; i--) { sum = 0;

Page 31: Classical CryptoAlgorithms (Ch 01-12)

for (j = i + 1; j < n; j++) sum += (m[i][j] * x[j]) % p; if (sum < 0) sum += p; x[i] = (d[i] * (b[i] - sum)) % p; if (x[i] < 0) x[i] += p; }}

int main(void){ char cipher[5][25] = {"LMQETXYEAGTXCTUIEWNC", /*THEKINGWASINTHECOUNT*/ "TXLZEWUAISPZYVAPEWLM", /*INGHOUSECOUNTINGOUTH*/ "GQWYAXFTCJMSQCADAGTX", /*ISMONEYTHEQUEENWASIN*/ "LMDXNXSNPJQSYVAPRIQS", /*THEPARLOUREATINGBREA*/ "MHNOCVAXFV"}; /*DANDHONEY*/ char ciphertext[100], lt_ch, rt_ch; long count = 0, d_count = 0, i, j, k, n = 4, p = 26; long di_freq[26][26] = {{0}}; long det, b[4], x[4]; long **I = create_square_matrix(n); long **K = create_square_matrix(n); struct digram *d, temp;

for (i = 0; i < 5; i++) for (j = 0; j < strlen(cipher[i]); j++) ciphertext[count++] = cipher[i][j]; for (i = 0; i < count; i++) ciphertext[i] -= (char) 'A'; for (i = 0; i < count; i += 2) { lt_ch = ciphertext[i]; rt_ch = ciphertext[i + 1]; di_freq[lt_ch][rt_ch]++; } for (i = 0; i < 26; i++) for (j = 0; j < 26; j++) if (di_freq[i][j] != 0) d_count++; d = calloc(d_count, sizeof(struct digram)); if (!d) { fprintf(stderr, "*error*\ninsufficient memory\n"); exit(1); } i = 0; for (j = 0; j < 26; j++) { for (k = 0; k < 26; k++) { if (di_freq[j][k] != 0) { d[i].alpha1 = j + 'A'; d[i].alpha2 = k + 'A'; d[i++].count = di_freq[j][k]; } } } /* sort the digrams using the selection sort */

Page 32: Classical CryptoAlgorithms (Ch 01-12)

for (i = 0; i < d_count - 1; i++) for (j = i + 1; j < d_count; j++) if (d[i].count < d[j].count) temp = d[i], d[i] = d[j], d[j] = temp; for (i = 0; i < d_count; i++) printf("%2ld %c %c %ld\n", i, d[i].alpha1, d[i].alpha2, d[i].count); K[0][0] = 'I' - 'A'; K[0][2] = 'N' - 'A'; K[1][1] = K[0][0]; K[1][3] = K[0][2]; K[2][0] = 'T' - 'A'; K[2][2] = 'H' - 'A'; K[3][1] = K[2][0]; K[3][3] = K[2][2]; b[0] = d[0].alpha1 - 'A'; b[1] = d[0].alpha2 - 'A'; b[2] = d[1].alpha1 - 'A'; b[3] = d[1].alpha2 - 'A'; gaussian_elimination(n, p, b, x, K); K[0][0] = x[0]; K[0][1] = x[1]; K[1][0] = x[2]; K[1][1] = x[3]; printf("the key matrix is:\n"); for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) printf("%2ld ", K[i][j]); printf("\n"); } det = (K[0][0] * K[1][1] - K[0][1] * K[1][0]) % p; if (det < 0) det += p; det = inv(det, p); if (det < 0) det += p; printf("det(K) = %ld\n", det); I[0][0] = (det * K[1][1]) % p; I[1][1] = (det * K[0][0]) % p; I[0][1] = - (det * K[0][1]) % p; I[1][0] = - (det * K[1][0]) % p; if (I[0][1] < 0) I[0][1] += p; if (I[1][0] < 0) I[1][0] += p; printf("the inverse key matrix is:\n"); for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) printf("%2ld ", I[i][j]); printf("\n"); } for (i = 0; i < count / 2; i++) { b[0] = I[0][0] * ciphertext[2 * i] + I[1][0] * ciphertext[2 * i + 1]; b[1] = I[0][1] * ciphertext[2 * i] + I[1][1] * ciphertext[2 * i + 1]; b[0] = b[0] % p + 'A'; b[1] = b[1] % p + 'A'; printf("%c%c", b[0], b[1]); if ((i + 1) % 10 == 0) printf("\n"); } delete_square_matrix(n, I);

Page 33: Classical CryptoAlgorithms (Ch 01-12)

delete_square_matrix(n, K); return 0;}

1.7 ex0107.c (3,002)

/* Author: Pate Williams (c) 1997

Exercise 1.7 "We describe a special case of a Permutation Cipher. Let m, n be positive integers. Write out the plain text, by rows in m by n rectangles. Then form the ciphertext by taking columns of these retangles. For example if m = 4, n = 3, then we would encrypt the plaintext "cryptography" by forming the following rectangle: cryp togr aphy The ciphertext would be "CTAROPYGHPRY". (a) Describe how Bob would decrypt a ciphertext (given values for m and n). (b) Decrypt the following ciphertext, which was obtained by using this method of encryption: MYAMRARUYIQTENCTORAHROYWDSOYEOUARRGDERNOGW" -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 42.*/

#include <ctype.h>#include <stdio.h>#include <string.h>

int main(void){ char cipher[2][24] = {"MYAMRARUYIQTENCTORAH", "ROYWDSOYEOUARRGDERNOGW"}; char answer[256], ciphertext[50], grid[50][50]; char test_ciphertext[16] = "CTAROPYGHPRY"; char plain[2][24] = {"MARYMARYQUITECONTRARY", "HOWDOESYOURGARDENGROW"}; char plaintext[50]; int found = 0; long count = 0, i, j, k = 0, m = 4, n = 3;

for (j = 0; j < m; j++) for (i = 0; i < n; i++) grid[i][j] = test_ciphertext[k++]; for (i = 0; i < n; i++) for (j = 0; j < m; j++) printf("%c", grid[i][j]); printf("\n"); for (i = 0; i < 2; i++)

Page 34: Classical CryptoAlgorithms (Ch 01-12)

for (j = 0; j < strlen(cipher[i]); j++) ciphertext[count++] = cipher[i][j]; printf("count = %ld\n", count); for (n = 2; !found && n < count; n++) { if (count % n == 0) { k = 0; m = count / n; for (j = 0; j < m; j++) for (i = 0; i < n; i++) grid[i][j] = ciphertext[k++]; for (i = 0; i < n; i++) { for (j = 0; j < m; j++) printf("%c", grid[i][j]); printf("\n"); } for (i = 0; i < n; i++) for (j = 0; j < m; j++) printf("%c", grid[i][j]); printf("\n"); printf("another value of n = %ld (n or y)? ", n); scanf("%s", answer); found = tolower(answer[0] == 'n'); } } count = 0; for (i = 0; i < 2; i++) for (j = 0; j < strlen(plain[i]); j++) plaintext[count++] = plain[i][j]; found = 0; for (n = 2; !found && n < count; n++) { if (count % n == 0) { k = 0; m = count / n; for (i = 0; i < n; i++) for (j = 0; j < m; j++) grid[i][j] = plaintext[k++]; for (i = 0; i < n; i++) { for (j = 0; j < m; j++) printf("%c", grid[i][j]); printf("\n"); } for (j = 0; j < m; j++) for (i = 0; i < n; i++) printf("%c", grid[i][j]); printf("\n"); printf("next value of n = %ld (n or y)? ", n); scanf("%s", answer); found = tolower(answer[0]) == 'n'; } } return 0;}

1.8 ex0108.c (1,169)

/*

Page 35: Classical CryptoAlgorithms (Ch 01-12)

Author: Pate Williams (c) 1997

Exercise 1.8 "There are eight different linear recurrences over Z_2 of degree four having c0 = 1. Deter- mine which of these recurrences give rise to a keystream of period 15 (given a non-zero initialization vector)." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 42.*/

#include <stdio.h>

int main(void){ int found; long c0 = 1, c1, c2, c3, i, j, z[50];

z[0] = 1, z[1] = z[2] = z[3] = 0; for (c1 = 0; c1 < 2; c1++) { for (c2 = 0; c2 < 2; c2++) { for (c3 = 0; c3 < 2; c3++) { printf("1%ld%ld%ld 1000", c1, c2, c3); for (i = 0; i < 32; i++) { z[i + 4] = (c0 * z[i] + c1 * z[i + 1] + c2 * z[i + 2] + c3 * z[i + 3]) % 2; printf("%ld", z[i + 4]); } for (i = 2; i <= 15; i++) { found = 1; for (j = 0; found && j < i; j++) found = z[j] == z[j + i]; if (found) { j = i; break; } } if (found) printf(" %ld\n", j); } } } return 0;}

1.10 ex0110.c (1,031)

/* Author: Pate Williams (c) 1997

Exercise 1.10 "Decrypt the following ciphertext, obtained from the Autokey Cipher, by using exhaustive key search: MALVVMAFBHBUQPTSOXALTGVWWRG" -Douglas R. Stinson-

Page 36: Classical CryptoAlgorithms (Ch 01-12)

See "Cryptography: Theory and Practice" by Douglas R. Stinson page 43.*/

#include <ctype.h>#include <stdio.h>#include <string.h>

int main(void){ char answer[256]; char ciphertext[] = "MALVVMAFBHBUQPTSOXALTGVWWRG"; int found = 0; long count = strlen(ciphertext), i, j, x, y;

for (i = 0; i < count; i++) ciphertext[i] -= (char) 'A'; for (i = 0; !found && i < 26; i++) { x = (ciphertext[0] - i) % 26; if (x < 0) x += 26; printf("%c", x + 'A'); for (j = 1; j < count; j++) { y = (ciphertext[j] - x) % 26; if (y < 0) y += 26; printf("%c", y + 'A'); x = y; } printf("\n"); printf("another key = %c (n or y)? ", i + 'A'); scanf("%s", answer); found = tolower(answer[0]) == 'n'; } return 0;}

Chapter 03 The Data Encryption Standard

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 Example 3.3 and/or Exercise 3.8 by e-mailing me at [email protected] Please specify the either dc3.c and/or dc4.c and MIME or UUencoded format for the return e-mail attachment, or request that I put the source code in an e-mail if your system does not handle attachments. 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. The current versions of these differential cryptanalytic programs work on little-endian processors such as the Intel family of processors.

Page 37: Classical CryptoAlgorithms (Ch 01-12)

Chapter 04 The RSA System and Factoring

4.1 ex0401.c (1,157)

4.2 ex0402.c (1,349)

4.6 ex0406.c (3,999)

4.7 ex0407.c (2,613)

4.8 ex0408.c (2,798)

4.12 ex0412.c (1,157)

4.13 ex0413.c (1,363)

4.16 ex0416.c (1,684)

4.18 ex0418.c (4,454)

4.19 ex0419.c (1,420)

Exercises

4.1 ex0401.c (1,157)

/* Author: Pate Williams (c) 1997

Exercise "4.1 Use the Extended Euclidean algorithm to compute the following multiplicative inverses: (a) 17 ^ - 1 mod 101 (b) 357 ^ - 1 mod 1234 (c) 3125 ^ - 1 mod 9987." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 157.*/

#include <stdio.h>

long Extended_Euclidean(long b, long n){

Page 38: Classical CryptoAlgorithms (Ch 01-12)

long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

int main(void){ long b[3] = {17, 357, 3125}; long n[3] = {101, 1234, 9987}; long i, x, y;

for (i = 0; i < 3; i++) { x = Extended_Euclidean(b[i], n[i]); printf("the inverse of %4ld modulo %4ld = %4ld\n", b[i], n[i], x); y = (x * b[i]) % n[i]; if (y != 1) printf("*error*\nin inverse calculation\n"); } return 0;}

4.2 ex0402.c (1,349)

/* Author: Pate Williams (c) 1997

Exercise "4.2 Solve the following system of congruences: x = 12 (mod 25) x = 9 (mod 26) x = 23 (mod 27)." -Douglas R. Sinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 157.*/

#include <stdio.h>

#define SIZE 256l

long Extended_Euclidean(long b, long n){

Page 39: Classical CryptoAlgorithms (Ch 01-12)

long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

long Chinese_Remainder(long r, long *a, long *m){ long i, N = 1, M[SIZE], y[SIZE], x = 0;

for (i = 0; i < r; i++) N *= m[i]; for (i = 0; i < r; i++) { M[i] = N / m[i]; y[i] = Extended_Euclidean(M[i], m[i]); x += (a[i] * M[i] * y[i]) % N; } return x;}

int main(void){ long a[3] = {12, 9, 23}; long m[3] = {25, 26, 27}; long i, r = 3, x;

x = Chinese_Remainder(r, a, m); for (i = 0; i < 3; i++) { printf("x = %2ld mod %2ld\n", a[i], m[i]); if (x % m[i] != a[i]) printf("*error\nin CRT calculation\n"); } printf("x = %ld\n", x); return 0;}

4.6 ex0406.c (3,999)

/* Author: Pate Williams (c) 1997

Page 40: Classical CryptoAlgorithms (Ch 01-12)

Exercise "4.6 Two samples of RSA cipertext are presented in Tables 4.1 and 4.2. Your task is to decrypt them. The public parameters of the system are n = 18923 and b = 1261 (for Table 4.1) and n = 31313 and b = 4913 (for Table 4.2)." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson pages 157-158.*/

#include <math.h>#include <stdio.h>

#define BITS_PER_LONG 32l#define BITS_PER_LONG_1 31l

long get_bit(long i, long *sieve){ long b = i % BITS_PER_LONG; long c = i / BITS_PER_LONG;

return (sieve[c] >> (BITS_PER_LONG_1 - b)) & 1;}

void set_bit(long i, long v, long *sieve){ long b = i % BITS_PER_LONG; long c = i / BITS_PER_LONG; long mask = 1 << (BITS_PER_LONG_1 - b);

if (v == 1) sieve[c] |= mask; else sieve[c] &= ~mask;}

void Sieve(long n, long *sieve){ long c, i, inc;

set_bit(0l, 0l, sieve); set_bit(1l, 0l, sieve); set_bit(2l, 1l, sieve); for (i = 3; i <= n; i++) set_bit(i, i & 1, sieve); c = 3; do { i = c * c, inc = c + c; while (i <= n) { set_bit(i, 0l, sieve); i += inc; } c += 2; while (!get_bit(c, sieve)) c++; } while (c * c <= n);}

Page 41: Classical CryptoAlgorithms (Ch 01-12)

long factor(long n, long *sieve)/* factor using trial division */{ int found = 0; long p = 0, s = sqrt(n);

while (!found && p <= s) { while (!get_bit(p, sieve)) p++; found = n % p == 0; if (!found) p++; } return p;}

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } return a;}

int main(void){ char abc[26] = "abcdefghijklmnopqrstuvwxyz"; long b[2] = {1261l, 4913l}; long n[2] = {18923l, 31313l}; long c[2][32] = {{12423l, 11524l, 7243l, 7459l, 14303l, 6127l, 10964l, 16399l, 9792l, 13629l, 14407l, 18817l, 18830l, 13556l, 3159l, 16647l,

Page 42: Classical CryptoAlgorithms (Ch 01-12)

5300l, 13951l, 81l, 8986l, 8007l, 13167l, 10022l, 17213l, 2264l, 961l, 17459l, 4101l, 2999l, 14569l, 17183l, 15827l}, { 6340l, 8309l, 14010l, 8936l, 27358l, 25023l, 16481l, 25809l, 23614l, 7135l, 24996l, 30590l, 27570l, 26486l, 30388l, 9395l, 27584l, 14999l, 4517l, 12146l, 29421l, 26439l, 1606l, 17881l, 25774l, 7647l, 23901l, 7372l, 25774l, 18436l, 12056l, 13547l}}; long i, j, sieve[10000], m, p, q; long a, bi, ni, phi, t;

Sieve(n[1], sieve); for (i = 0; i < 2; i++) { bi = b[i]; ni = n[i]; p = factor(ni, sieve); q = ni / p; printf("p = %5ld q = %5ld n = %5ld\n", p, q, ni); phi = (p - 1) * (q - 1); a = Extended_Euclidean(bi, phi); printf("a = %5ld b = %5ld\n", a, bi); printf("%5ld * %5ld mod %5ld = %5ld\n", a, bi, phi, (a * bi) % phi); for (j = 0; j < 32; j++) { m = exp_mod(c[i][j], a, ni); if (c[i][j] != exp_mod(m, bi, ni)) printf("*error*\in RSA\n"); t = m / 676l; m = m % 676l; printf("%c", abc[t]); t = m / 26l; m = m % 26l; printf("%c", abc[t]); printf("%c", abc[m]); if ((j + 1) % 8 == 0) printf("\n"); } printf("\n"); } return 0;}

4.7 ex0407.c (2,613)

/* Author: Pate Williams (c) 1997

Exercise "4.7 This exercise exhibits what is called a protocol failure. Suppose Bob has an RSA Cyyptosystem with a large modulus n for which the factorization cannot be found in a reasonable amount of time. Suppose Alice sends

Page 43: Classical CryptoAlgorithms (Ch 01-12)

a message to Bob represnting each alphabetic character as an integer between 0 and 25, and then encrypting each residue modulo 26 as a separate plaintext character. (a) describe how Oscar can easily decrypt a message that is encrypted in this way. (b) Illustrate the attack by decrypting the following ciphertext (which was encrypted using a RSA Cryptosystem with n = 18721 and b = 25) without factoring the modulus: 365, 0, 4845, 14930, 2608, 2608, 0." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson pages 158-159.*/

#include <stdio.h>#include <stdlib.h>

struct data {long c; long l;};

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } return a;}

int fcmp(const void *d1, const void *d2){ struct data *data1 = (struct data *) d1; struct data *data2 = (struct data *) d2;

if (data1->l < data2->l) return - 1; if (data1->l > data2->l) return + 1; return 0;}

void decrypt(long b, long length, long n, long *c){ long i; struct data d[26], e, *p;

/* create a table of possible ciphertext values */ for (i = 0; i < 26; i++) { d[i].c = 'a' + i; d[i].l = exp_mod(i, b, n); } /* sort the table on the ciphertext value */ qsort(d, 26, sizeof(struct data), fcmp);

Page 44: Classical CryptoAlgorithms (Ch 01-12)

printf("the possible cipher characters are as follows:\n"); for (i = 0; i < 26; i++) { printf("%c %5ld ", d[i].c, d[i].l); if ((i + 1) % 4 == 0) printf("\n"); } printf("\nthe decrypted message is as follows:\n"); for (i = 0; i < length; i++) { e.c = 'a'; e.l = c[i]; p = bsearch(&e, d, 26, sizeof(struct data), fcmp); if (!p) { fprintf(stderr, "fatal error\n"); fprintf(stderr, "binary search failed\n"); exit(1); } printf("%c", p->c); }}

int main(void){ long b = 25, i, n = 18721; long c[7] = {365, 0, 4845, 14930, 2608, 2608, 0}; long length = 7;

printf("b = %5ld n = %5ld\n", b, n); printf("the ciphertext is as follows:\n"); for (i = 0; i < length; i++) printf("%5ld ", c[i]); printf("\n"); decrypt(b, length, n, c); return 0;}

4.8 ex0408.c (2,798)

/* Author: Pate Williams (c) 1997

Exercise "4.8 This exercise illustrates another example of a protocol failure (due to Simmons) involving RSA; it is called the common modulus protocol failure. Suppose Bob has an RSA Cryptosystem with modulus n and encryption exponent b1, and Charlie has an RSA Cryptosystem with (the same) modulus n and encryption exponent b2. Suppose that gcd(b1, b2) = 1. Now, consisder the situation that arises if Alice encrypts the same plaintext x to send to both Bob and Charlie. Thus, she computes y1 = x ^ b1 mod n and y2 = x ^ b2 mod n, and sends y1 to Bob and y2 to Charlie. Suppose Oscar intercepts y1 and y2, and performs the following computations: 1. compute c1 = b1 ^ - 1 mod b2 2. compute c2 = (c1 * b1 - 1) / b2

Page 45: Classical CryptoAlgorithms (Ch 01-12)

3. compute x1 = y1 ^ c1 * (y2 ^ c2) ^ - 1 mod n (b) Illustrate this attack by computing x by this method if n = 18721, b1 = 945, b2 = 7717, y1 = 10510, and y2 = 14702." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 159.*/

#include <stdio.h>#include <stdlib.h>

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } return a;}

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

long gcd(long a, long b)/* Euclid's algorithm */{ long r;

while (b != 0) r = a % b, a = b, b = r; return a;}

int main(void)

Page 46: Classical CryptoAlgorithms (Ch 01-12)

{ long b1 = 945l, b2 = 7717l, n = 18721l; long y1 = 10510l, y2 = 14702l; long c1, c2, x, x1, x2;

if (gcd(b1, b2) != 1) { fprintf(stderr, "fatal error\n"); fprintf(stderr, "gcd(b1, b2) != 1\n"); exit(1); } c1 = Extended_Euclidean(b1, b2); c2 = (c1 * b1 - 1) / b2; x1 = exp_mod(y1, c1, n); x2 = exp_mod(y2, c2, n); x2 = Extended_Euclidean(x2, n); x = (x1 * x2) % n; x1 = exp_mod(x, b1, n); x2 = exp_mod(x, b2, n); printf("b1 = %5ld b2 = %5ld n = %ld\n", b1, b2, n); printf("c1 = %5ld c2 = %5ld\n", c1, c2); printf("y1 = %5ld y2 = %5ld x = %ld\n", y1, y2, x); printf("y1 = %5ld y2 = %5ld\n", x1, x2); if (x1 != y1 || x2 != y2) { fprintf(stderr, "fatal error\n"); fprintf(stderr, "can't compute y1 and y2 from x\n"); fprintf(stderr, "y1 %5ld y2 %5ld\n", x1, x2); exit(1); } return 0;}

4.12 ex0412.c (1,157)

/* Author: Pate Williams (c) 1997

Exercise "4.12 Write a program to evaluate Jacobi symbols using the four properties presented in Section 4.5. The program should not do any factoring, other than dividing out powers of two. Test your program by computing the following Jacobi symbols: (610 / 987), (20964 / 1987), (1234567 / 11111111)." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 160.*/

#include <stdio.h>

int JACOBI(long a, long n){ int s; long a1, b = a, e = 0, m, n1;

Page 47: Classical CryptoAlgorithms (Ch 01-12)

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 = + 1; else if (m == 3 || m == 5) s = - 1; if (n % 4 == 3 && a1 % 4 == 3) s = - s; if (a1 != 1) n1 = n % a1; else n1 = 1; return s * JACOBI(n1, a1);}

int main(void){ long a[3] = {610l, 20964l, 1234567l}; long n[3] = {987l, 1987l, 11111111l}; long i;

for (i = 0; i < 3; i++) printf("(%8ld / %8ld) = %+d\n", a[i], n[i], JACOBI(a[i], n[i])); return 0;}

4.13 ex0413.c (1,363)

/* Author: Pate Williams (c) 1997

Exercise "4.13 Write a program that computes the number of Euler pseudo-primes to the bases 837, 851, and 1189." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 160.*/

#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 = + 1; else if (m == 3 || m == 5) s = - 1; if (n % 4 == 3 && a1 % 4 == 3) s = - s;

Page 48: Classical CryptoAlgorithms (Ch 01-12)

if (a1 != 1) n1 = n % a1; else n1 = 1; return s * JACOBI(n1, a1);}

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } return a;}

int main(void){ int j; long a, c, i, n[3] = {837l, 851l, 1189l}; long n1, n2, ni, x;

for (i = 0; i < 3; i++) { c = 0; ni = n[i]; n1 = ni - 1; n2 = n1 >> 1; for (a = 2l; a < ni; a++) { x = exp_mod(a, n2, ni); j = JACOBI(a, ni); if (j == - 1 && x == n1) c++; else if (j == x) c++; } printf("%ld Euler pseudo-prime(s) base %4ld\n", c, ni); } return 0;}

4.16 ex0416.c (1,684)

/* Author: Pate Williams (c) 1997

Exercise "4.16 Suppose Bob has carelessly revealed his decryption exponent to be a = 14039 in an RSA Cryptosystem with public key n = 36581 and b = 4679. Implement the probabilistic algorithm to factor n given this information. Test your algorithm with the "random" choices w = 9983 and w = 13641. Show all computations." -Douglas R. Stinson- See "Cryptography: Theory and Practice by Douglas R. Stinson page 161.*/

Page 49: Classical CryptoAlgorithms (Ch 01-12)

#include <stdio.h>

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } return a;}

long gcd(long a, long b)/* Euclid's algorithm */{ long r;

while (b != 0) r = a % b, a = b, b = r; return a;}

int factor(long a, long b, long n, long w, long *x){ long r = a * b - 1, s = 0, v, v0;

*x = gcd(w, n); printf("x = %ld\n", *x); if (*x > 1 && *x < n) return 1; while (!(r & 1)) r >>= 1, s++; v = exp_mod(w, r, n); printf("w = %ld\n", w); printf("r = %ld\n", r); printf("s = %ld\n", s); printf("v = %ld\n", v); if (v == 1) return 0; while (v != 1) { v0 = v; v = (v * v) % n; printf("v0 = %ld\n", v0); printf("v = %ld\n", v); } if (v0 == n - 1) return 0; *x = gcd(v0 + 1, n); printf("x = %ld\n", *x); return 1;}

int main(void){ long a = 14039l, b = 4679l, n = 36581l; long w1 = 9983l, w2 = 13461l, x;

Page 50: Classical CryptoAlgorithms (Ch 01-12)

printf("success = %d\n", factor(a, b, n, w1, &x)); printf("success = %d\n", factor(a, b, n, w2, &x)); return 0;}

4.18 ex0418.c (4,454)

/* Author: Pate Williams (c) 1997

Exercise "4.18 Suppose p = 199, q = 211, and B = 1357 in the Rabin Cryptosystem. Perform the following computations. (a) Determine the four square roots of 1 modulo n, where n = pq. (b) Compute the encryption y = ek(32767). (c) Determine the four possible decryptions of this given ciphetext." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 161.*/

#include <math.h>#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 = + 1; else if (m == 3 || m == 5) s = - 1; if (n % 4 == 3 && a1 % 4 == 3) s = - s; if (a1 != 1) n1 = n % a1; else n1 = 1; return s * JACOBI(n1, a1);}

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

if (b == 0) return 1; while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1;

Page 51: Classical CryptoAlgorithms (Ch 01-12)

if (b != 0) s = (s * s) % n; } return a;}

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 (x < 0) x += n; if (d == 1) return x; return 0;}

void sqrt_mod(long a, long p, long *r){ long ai, b, c, d, i, p1 = p - 1, s = 0, t = p1; long x, y;

if (JACOBI(a, p) == - 1) { *r = 0; return; } do do b = rand() % p; while (b == 0); while (JACOBI(b, p) != - 1); while (!(t & 1)) t >>= 1, s++; ai = inverse(a, p); if ((ai * a) % p != 1) { printf("*error*\nin inverse\n"); printf("a = %ld a ^ - 1 = %ld\n", a, ai); } c = exp_mod(b, t, p); *r = exp_mod(a, (t + 1) >> 1, p); x = pow(2l, s);

Page 52: Classical CryptoAlgorithms (Ch 01-12)

for (i = 1; i < s; i++) { y = (((*r * *r) % p) * ai) % p; d = exp_mod(y, x, p); if (d < 0) d += p; if (d == p1) *r = (*r * c) % p; c = (c * c) % p; x *= 2; } if (*r < 0) *r += p;}

void square_roots(long a, long p, long q, long *x1, long *x2, long *y1, long *y2){ long b, c, d, e, n = p * q, r, s, x, y;

if (a < p) b = a; else b = a % p; sqrt_mod(b, p, &r); if ((r * r) % p != b) { printf("*error*\nin sqrt_mod p\n"); printf("(a / p) = %d\n", JACOBI(a, p)); printf("%ld * %ld %% %ld = %ld\n", r, r, p, (r * r) % p); } if (a < q) b = a; else b = a % q; sqrt_mod(b, q, &s); if ((s * s) % q != b) { printf("*error*\nin sqrt_mod q\n"); printf("(a / q) = %d\n", JACOBI(a, q)); printf("%ld * %ld %% %ld = %ld\n", s, s, q, (s * s) % q); } extended_euclid(p, q, &c, &d, &e); x = (r * d * q + s * c * p) % n; y = (r * d * q - s * c * p) % n; *x1 = x; *x2 = - x % n; if (*x1 < 0) *x1 += n; if (*x2 < 0) *x2 += n; *y1 = y; *y2 = - y % n; if (*y1 < 0) *y1 += n; if (*y2 < 0) *y2 += n;}

int main(void){ long B = 1357l, B2, B4; long a = 1l, p = 199l, q = 211l; long i, n = p * q, s[4]; long x = 32767l, y, z;

square_roots(a, p, q, &s[0], &s[1], &s[2], &s[3]); printf("the four square roots of %ld mod %ld are:\n", a, n); for (i = 0; i < 4; i++) { printf("%5ld ", s[i]);

Page 53: Classical CryptoAlgorithms (Ch 01-12)

if ((s[i] * s[i]) % n != a) printf("*error*\nin square_roots\n"); } B2 = (B * inverse(2l, n)) % n; B4 = (((B * B) % n) * inverse(4l, n)) % n; y = (x * ((x + B) % n)) % n; printf("\nek(%5ld) = %5ld\n", x, y); z = (B4 + y) % n; square_roots(z, p, q, &s[0], &s[1], &s[2], &s[3]); printf("the four possible plaintexts are:\n"); for (i = 0; i < 4; i++) { z = (s[i] - B2) % n; if (z < 0) z += n; printf("%5ld ", z); if ((z * (z + B)) % n != y) printf("*error*\nin square_roots\n"); } return 0;}

4.19 ex0419.c (1,420)

/* Author: Pate Williams (c) 1997

Exercise "4.19 Factor 262063 and 9420457 using the p - 1 method. How big does B have to be each case to be successful." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 161.*/

#include <stdio.h>

#define B_MAX 10000l

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } return a;}

long gcd(long a, long b)/* Euclid's algorithm */{ long r;

while (b != 0)

Page 54: Classical CryptoAlgorithms (Ch 01-12)

r = a % b, a = b, b = r; return a;}

int p_1(long B, long n, long *d){ long a = 2, j;

for (j = 2; j <= B; j++) a = exp_mod(a, j, n); *d = gcd(a - 1, n); if (*d > 1 && *d < n) return 1; return 0;}

int main(void){ int found; long B, d, e, i, ni; long n[2] = {262063l, 9420457l};

for (i = 0; i < 2; i++) { ni = n[i]; found = 0; for (B = 2; !found && B <= B_MAX; B++) found = p_1(B, ni, &d); if (found) { e = ni / d; if (d * e != ni) printf("*error*\in p_1\n"); else { printf("%7ld = %4ld * %4ld ", ni, d, e); printf("B = %3ld\n", B); } } else printf("%ld not factored in %ld attempts\n", ni, B_MAX - 1); } return 0;}

Chapter 05 Other Public-key Cryptosystems

5.1 te0501.c (3,315)

5.7 te0507.c (5,097)

5.1 ex0501.c freelip (3,062)

5.2 ex0502.c (4,680)

Page 55: Classical CryptoAlgorithms (Ch 01-12)

5.3 ex0503.c (2,138)

5.4 ex0504.c (3,154)

5.5 ex0505.txt (517)

5.6 ex0506.c (5,773)

5.7 ex0507.c (7,323)

5.8 ex0508.c (4,813)

5.9 ex0509.c (6,316)

5.10 ex0510.c (2,658)

5.11 ex0511.c (4,425)

5.1 te0501.c (3,315)

/* Author: Pate Williams (c) 1997

"Example 5.2. Suppose p = 809, and we wish to find log(3, 525)." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson pages 165 - 166.*/

#include <math.h>#include <stdio.h>#include <stdlib.h>

struct data {long j, alpha_j;};

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */

Page 56: Classical CryptoAlgorithms (Ch 01-12)

{ long a = 1l, s = x;

while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } if (a < 0) a += n; return a;}

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

int fcmp(const void *d1, const void *d2){ struct data *data1 = (struct data *) d1; struct data *data2 = (struct data *) d2;

if (data1->alpha_j < data2->alpha_j) return - 1; if (data1->alpha_j > data2->alpha_j) return + 1; return 0;}

long Shanks(long alpha, long beta, long p)/* returns log(alpha, beta) in Z_p where alpha is a generator and beta is in Z_p */{ long a, alpha_i, i, log, m = ceil(sqrt(p - 1)); struct data *table1 = calloc(m, sizeof(struct data)); struct data *table2 = calloc(m, sizeof(struct data)); struct data *d, key;

if (!table1 || !table2) { fprintf(stderr, "*error*\nin sufficient memory\n"); fprintf(stderr, "from Shanks\n"); exit(1); }

Page 57: Classical CryptoAlgorithms (Ch 01-12)

/* create a logarithm table */ alpha_i = exp_mod(alpha, m, p); for (i = 0; i < m; i++) { table1[i].j = i; table1[i].alpha_j = exp_mod(alpha_i, i, p); } alpha_i = Extended_Euclidean(alpha, p); if ((alpha_i * alpha) % p != 1) { fprintf(stderr, "*error*\nin Extended_Euclidean\n"); exit(1); } for (i = 0; i < m; i++) { table2[i].j = i; a = exp_mod(alpha_i, i, p); table2[i].alpha_j = (beta * a) % p; } for (i = 0; i < m; i++) { printf("(%3ld, %3ld) ", table1[i].j, table1[i].alpha_j); if ((i + 1) % 5 == 0) printf("\n"); } printf("\n"); for (i = 0; i < m; i++) { printf("(%3ld, %3ld) ", table2[i].j, table2[i].alpha_j); if ((i + 1) % 5 == 0) printf("\n"); } printf("\n"); /* sort the tables by second data item */ qsort(table1, m, sizeof(struct data), fcmp); qsort(table2, m, sizeof(struct data), fcmp); for (i = 0; i < m; i++) { key.j = table1[i].j; key.alpha_j = table1[i].alpha_j; d = bsearch(&key, table2, m, sizeof(struct data), fcmp); if (d) { log = (key.j * m + d->j) % (p - 1); printf("log(%3ld, %3ld) = %2ld * %2ld + %ld\n", alpha, beta, m, key.j, d->j); printf(" = %3ld in Z_p%3ld\n", log, p); if (exp_mod(alpha, log, p) == beta) return log; } } return 0;}

int main(void){ long alpha = 3, beta = 525l, p = 809l, log;

log = Shanks(alpha, beta, p); if (log == 0) printf("log(%3ld, %3ld) in Z_%3ld does not exist\n", alpha, beta, p); return 0;}

Page 58: Classical CryptoAlgorithms (Ch 01-12)

5.7 te0507.c (5,097)

/* Author: Pate Williams (c) 1997

Example 5.7 "Let E be the elliptic curve y ^ 2 = x ^ 3 + x + 6 defined over Z_11. (a) Determine the number of points on E. (b) Show that E a cyclic group. -Dougals R. Stinson- See "Cryptography: Theory and Practice by Douglas R. Stinson pages 185-186.*/

#include <math.h>#include <stdio.h>#include <stdlib.h>

#define MAX_POINTS 142l

struct point {long x, y;};

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 = + 1; else if (m == 3 || m == 5) s = - 1; if (n % 4 == 3 && a1 % 4 == 3) s = - s; if (a1 != 1) n1 = n % a1; else n1 = 1; return s * JACOBI(n1, a1);}

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

if (b == 0) return 1; while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } if (a < 0) a += n; return a;}

Page 59: Classical CryptoAlgorithms (Ch 01-12)

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

long E_points(long a, long b, long p, struct point *e)/* returns the number of points on the elliptic curve y ^ 2 = x ^ 3 + ax + b mod p */{ long count = 0, m = (p + 1) / 4, x, y;

if (p % 4 == 3) { for (x = 0; x < p; x++) { y = x * x * x + a * x + b; if (JACOBI(y, p) != - 1) { y = exp_mod(y, m, p); printf("(%2ld, %2ld) ", x, y); e[count].x = x; e[count].y = y; y = - y % p; if (y < 0) y += p; printf("(%2ld, %2ld) ", x, y); e[count + 1].x = x; e[count + 1].y = y; count += 2; if (count % 4 == 0) printf("\n"); } } if (count % 4 != 0) printf("\n"); } return count;}

void add(long a, long p, struct point P, struct point Q, struct point *R)/* elliptic curve point partial addition */{ long i, lambda;

Page 60: Classical CryptoAlgorithms (Ch 01-12)

if (P.x == Q.x && P.y == 0 && Q.y == 0) { R->x = 0; R->y = 1; return; } if (P.x == Q.x && P.y == p - Q.y) { R->x = 0; R->y = 1; return; } if (P.x == 0 && P.y == 1) { *R = Q; return; } if (Q.x == 0 && Q.y == 1) { *R = P; return; } if (P.x != Q.x) { i = Q.x - P.x; if (i < 0) i += p; i = Extended_Euclidean(i, p); lambda = ((Q.y - P.y) * i) % p; } else { i = Extended_Euclidean((2 * P.y) % p, p); lambda = ((3 * P.x * P.x + a) * i) % p; } if (lambda < 0) lambda += p; R->x = (lambda * lambda - P.x - Q.x) % p; R->y = (lambda * (P.x - R->x) - P.y) % p; if (R->x < 0) R->x += p; if (R->y < 0) R->y += p;}

void multiply(long a, long k, long p, struct point P, struct point *R){ struct point S;

R->x = 0; R->y = 1; S = P; while (k != 0) { if (k & 1) add(a, p, *R, S, R); k >>= 1; if (k != 0) add(a, p, S, S, &S); }}

long order(long a, long p, struct point P){ long ord = 1; struct point Q = P, R;

do {

Page 61: Classical CryptoAlgorithms (Ch 01-12)

ord++; add(a, p, P, Q, &R); Q = R; } while (R.x != 0 && R.y != 1); return ord;}

int main(void){ long a = 1, b = 6, h, i, j, p = 11; long max_order, min_order, noncyclic, ord; struct point e[MAX_POINTS], P, Q, R;

printf("E: y ^ 2 = x ^ 3 + %ld * x + %ld mod %ld\n", a, b, p); printf("the the non-origin points (x, y) on E are:\n"); h = E_points(a, b, p, e) + 1; printf("the number of non-origin points on E is: %ld\n", h - 1); max_order = 0; min_order = h + 1; printf("the non-origin points (x, y) on E "); printf("and their orders are:\n"); for (i = 0; i < h - 1; i++) { ord = order(a, p, e[i]); if (ord < h) noncyclic = 1; if (ord < min_order) { P = e[i]; min_order = ord; } if (ord > max_order) { Q = e[i]; max_order = ord; } printf("(%2ld, %2ld) %2ld ", e[i].x, e[i].y, ord); if ((i + 1) % 3 == 0) printf("\n"); } if (noncyclic) printf("E is not a cyclic group\n"); printf("minimum order: %ld\n", min_order); printf("maximum order: %ld\n", max_order); printf("minimum (%2ld, %2ld)\n", P.x, P.y); printf("maximum (%2ld, %2ld)\n", Q.x, Q.y); P.x = 2; P.y = 7; Q = P; for (i = 0, j = 1; i < 12; i++) { add(a, p, P, Q, &R); if (i == 0) printf("%2ld alpha = (%2ld, %2ld) ", j, P.x, P.y); j++; if (j <= h) printf("%2ld alpha = (%2ld, %2ld) ", j, R.x, R.y); Q = R; if (j % 3 == 0) printf("\n"); } return 0;

Page 62: Classical CryptoAlgorithms (Ch 01-12)

}

Exercises

5.1 ex0501.c freelip (3,062)

/* Author: Pate Williams (c) 1997

Exercise "5.1 Implement Shanks's algorithm for finding discrete logarithms in Z_p, where p is prime and alpha is a primitive element. Use your program to find log(106, 12375) in Z_24691 and log(6, 248388) in Z_458009." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 200.*/

#include <math.h>#include <stdio.h>#include <stdlib.h>#include "lip.h"

struct data {long j, alpha_j;};

int fcmp(const void *d1, const void *d2){ struct data *data1 = (struct data *) d1; struct data *data2 = (struct data *) d2;

if (data1->alpha_j < data2->alpha_j) return - 1; if (data1->alpha_j > data2->alpha_j) return + 1; return 0;}

long Shanks(long alpha, long beta, long p)/* returns log(alpha, beta) in Z_p where alpha is a generator and beta is in Z_p */{ int found = 0; long i, log, m = ceil(sqrt(p - 1)); struct data *table1 = calloc(m, sizeof(struct data)); struct data *table2 = calloc(m, sizeof(struct data)); struct data *d, key; verylong za = 0, zb = 0, zc = 0, zp = 0; verylong zalpha = 0, zalpha_i = 0; verylong zbeta = 0, zp1 = 0;

if (!table1 || !table2) { fprintf(stderr, "*error*\nin sufficient memory\n"); fprintf(stderr, "from Shanks\n"); exit(1); }

Page 63: Classical CryptoAlgorithms (Ch 01-12)

/* create a logarithm table */ zintoz(alpha, &zalpha); zintoz(beta, &zbeta); zintoz(p, &zp); zintoz(p - 1, &zp1); zsexpmod(zalpha, m, zp, &zalpha_i); for (i = 0; i < m; i++) { table1[i].j = i; zsexpmod(zalpha_i, i, zp, &za); table1[i].alpha_j = ztoint(za); } zinvmod(zalpha, zp, &zalpha_i); for (i = 0; i < m; i++) { table2[i].j = i; zsexpmod(zalpha_i, i, zp, &za); zmulmod(zbeta, za, zp, &zb); table2[i].alpha_j = ztoint(zb); } /* sort the tables by second data item */ qsort(table1, m, sizeof(struct data), fcmp); qsort(table2, m, sizeof(struct data), fcmp); for (i = 0; !found && i < m; i++) { key.j = table1[i].j; key.alpha_j = table1[i].alpha_j; d = bsearch(&key, table2, m, sizeof(struct data), fcmp); if (d) { zintoz(key.j, &za); zintoz(m, &zb); zmulmod(za, zb, zp1, &zc); zintoz(d->j, &za); zaddmod(za, zc, zp1, &zb); log = ztoint(zb); zsexpmod(zalpha, log, zp, &za); found = zcompare(za, zbeta) == 0; } } if (!found) log = 0; zfree(&za); zfree(&zb); zfree(&zc); zfree(&zp); zfree(&zalpha); zfree(&zalpha_i); zfree(&zbeta); zfree(&zp1); return log;}

int main(void){ long alpha[2] = {106l, 6l}; long beta[2] = {12375l, 248388l}; long p[2] = {24691l, 458009l}; long i, log;

for (i = 0; i < 2; i++) { log = Shanks(alpha[i], beta[i], p[i]);

Page 64: Classical CryptoAlgorithms (Ch 01-12)

if (log != 0) printf("log(%6ld, %6ld) = %6ld in Z_%6ld\n", alpha[i], beta[i], log, p[i]); else printf("log(%6ld, %6ld) in Z_%6ld does not exist\n", alpha[i], beta[i], p[i]); } return 0;}

5.2 ex0502.c (4,680)

/* Author: Pate Williams (c) 1997

Exercise "5.2 Implement Pohlig-Hellman algorithm for finding discrete logarithms in Z_p, where p is prime and alpha is a primitive element. Use your program to find log(5, 8563) in Z_28703 and log(10, 12611) in Z_31153." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 200.*/

#include <math.h>#include <stdio.h>#include <stdlib.h>

#define BITS_PER_LONG 32l#define BITS_PER_LONG_1 31l#define SIZE 32l

struct factor {long expon, prime;};

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

Page 65: Classical CryptoAlgorithms (Ch 01-12)

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } return a;}

long get_bit(long i, long *sieve){ long b = i % BITS_PER_LONG; long c = i / BITS_PER_LONG;

return (sieve[c] >> (BITS_PER_LONG_1 - b)) & 1;}

void set_bit(long i, long v, long *sieve){ long b = i % BITS_PER_LONG; long c = i / BITS_PER_LONG; long mask = 1 << (BITS_PER_LONG_1 - b);

if (v == 1) sieve[c] |= mask; else sieve[c] &= ~mask;}

void Sieve(long n, long *sieve){ long c, i, inc;

set_bit(0l, 0l, sieve); set_bit(1l, 0l, sieve); set_bit(2l, 1l, sieve); for (i = 3; i <= n; i++) set_bit(i, i & 1, sieve); c = 3; do { i = c * c, inc = c + c; while (i <= n) { set_bit(i, 0l, sieve); i += inc; } c += 2; while (!get_bit(c, sieve)) c++; } while (c * c <= n);}

void factor(long n, long *sieve, struct factor *f, long *count)/* factor using trial division */

Page 66: Classical CryptoAlgorithms (Ch 01-12)

{ int one = 0; long e, p = 2, s = sqrt(n);

*count = 0; while (!one && p <= s) { while (!get_bit(p, sieve)) p++; if (n % p == 0) { e = 0; do { e++; n = n / p; } while (n % p == 0); f[*count].expon = e; f[*count].prime = p; *count = *count + 1; one = n == 1; } p++; }}

long Chinese_Remainder(long r, long *a, long *m){ long i, N = 1, M[SIZE], y[SIZE], x = 0;

for (i = 0; i < r; i++) N *= m[i]; for (i = 0; i < r; i++) { M[i] = N / m[i]; y[i] = Extended_Euclidean(M[i], m[i]); x += (a[i] * M[i] * y[i]) % N; } return x;}

long Pohlig_Hellman(long alpha, long beta, long c, long p, long q){ long ai, delta, e1, s = 0; long i, j, p1 = p - 1, p2 = p1 / q, q1 = q; long *a = calloc(c, sizeof(long)); long *betaj = calloc(c, sizeof(long)); long *gamma = calloc(q, sizeof(long));

if (!betaj || !gamma) { fprintf(stderr, "*error*\ninsufficient memory\n"); fprintf(stderr, "from Pohlig_Hellman\n"); exit(1); } ai = Extended_Euclidean(alpha, p); for (i = 0; i < q; i++) gamma[i] = exp_mod(alpha, i * p2, p); j = 0; betaj[j] = beta; while (j < c) { delta = exp_mod(betaj[j], p1 / q1, p); i = 0;

Page 67: Classical CryptoAlgorithms (Ch 01-12)

while (gamma[i] != delta) i++; a[j] = i; e1 = exp_mod(ai, i * q1 / q, p); betaj[j + 1] = (betaj[j] * e1) % p; q1 *= q; j++; } q1 = 1; for (i = 0; i < c; i++) { s += a[i] * q1; q1 *= q; } return s % exp_mod(q, c, p);}

int main(void){ long alpha[2] = {5l, 10l}; long beta[2] = {8563l, 12611l}; long p[2] = {28703l, 31153l}; long a[32], m[32]; long count, i, j, log, q, sieve[10000]; struct factor f[32];

Sieve(p[1], sieve); for (i = 0; i < 2; i++) { q = p[i] - 1; factor(q, sieve, f, &count); printf("the factorization of %ld is:\n", q); for (j = 0; j < count; j++) { printf("%ld", f[j].prime); if (f[j].expon > 1) printf(" ^ %ld\n", f[j].expon); else printf("\n"); } for (j = 0; j < count; j++) { a[j] = Pohlig_Hellman(alpha[i], beta[i], f[j].expon, p[i], f[j].prime); m[j] = exp_mod(f[j].prime, f[j].expon, p[i]); } log = Chinese_Remainder(count, a, m) % q; printf("log(%5ld, %5ld) = %5ld in Z%5ld\n", alpha[i], beta[i], log, p[i]); if (exp_mod(alpha[i], log, p[i]) != beta[i]) printf("*error*\nin calculation\n"); } return 0;}

5.3 ex0503.c (2,138)

/* Author: Pate Williams (c) 1997

Exercise "5.3 Find log(5, 896) in Z_1103 using the algorithm

Page 68: Classical CryptoAlgorithms (Ch 01-12)

presented in Figure 5.6, given that L_2(beta) = 1 for beta = 25, 219, 841, and L_2(beta) = 0 for beta = 163, 532, 625, and 656." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 200.*/

#include <stdio.h>

#define BITS_PER_LONG 32l

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } return a;}

long L_1(long beta, long p2, long p){ return exp_mod(beta, p2, p) != 1;}

long L_2(long beta){ if (beta == 25 || beta == 219 || beta == 841) return 1; return 0;}

Page 69: Classical CryptoAlgorithms (Ch 01-12)

long discrete_log(long alpha, long beta, long p){ long ai = Extended_Euclidean(alpha, p); long gamma; long p2 = (p - 1) >> 1, p4 = (p + 1) >> 2; long s, t = 2, x;

s = x = L_1(beta, p2, p); beta = (beta * exp_mod(ai, x, p)) % p; printf("beta = %4ld gamma = 0 x = %ld\n", beta, x); while (beta != 1) { x = L_2(beta); gamma = exp_mod(beta, p4, p); printf("beta = %4ld gamma = %4ld x = %ld\n", beta, gamma, x); if (L_1(gamma, p2, p) == x) beta = gamma; else beta = p - gamma; beta = (beta * exp_mod(ai, x, p)) % p; s += t * x; t *= 2; } return s;}

int main(void){ long alpha = 5l, beta = 896l, p = 1103l, log;

log = discrete_log(alpha, beta, p); printf("log(%ld, %ld) = %ld in Z_%ld\n", alpha, beta, log, p); if (exp_mod(alpha, log, p) != beta) printf("*error*\nin computation\n"); return 0;}

5.4 ex0504.c (3,154)

/* Author: Pate Williams (c) 1997

Exercise "5.4 Decrypt the ElGamal ciphertext presented in Table 5.3. The parameters of the system are p = 31847, alpha = 5, a = 7899, beta = 18074. Each element of Z_n represents three alphabetic characters as in Exercise 4.6." -Douglas R. Stinson- See "Cryptography: Theory and Practice by Douglas R. Stinson page 200.*/

#include <stdio.h>

struct ciphertext {long y1, y2;};

Page 70: Classical CryptoAlgorithms (Ch 01-12)

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } return a;}

long decrypt(long a, long p, struct ciphertext y){ long z = exp_mod(y.y1, a, p);

z = Extended_Euclidean(z, p); return (y.y2 * z) % p;}

int main(void){ char abc[26] = "abcdefghijklmnopqrstuvwxyz"; long a = 7899l, p = 31847l, i, t, x; struct ciphertext y[40] = {{ 3781l, 14409l}, {31552l, 3930l}, {27214l, 15442l}, { 5809l, 30274l}, { 5400l, 31486l}, {19936l, 721l}, {27765l, 29284l}, {29820l, 7710l}, {31590l, 26470l}, { 3781l, 14409l}, {15898l, 30844l}, {19048l, 12914l}, {16160l, 3129l}, { 301l, 17252l}, {24689l, 7776l}, {28856l, 15720l}, {30555l, 24611l}, {20501l, 2922l}, {13659l, 5015l}, { 5740l, 31233l},

Page 71: Classical CryptoAlgorithms (Ch 01-12)

{ 1616l, 14170l}, { 4294l, 2307l}, { 2320l, 29174l}, { 3036l, 20132l}, {14130l, 22010l}, {25910l, 19663l}, {19557l, 10145l}, {18899l, 27609l}, {26004l, 25056l}, { 5400l, 31486l}, { 9526l, 3019l}, {12962l, 15189l}, {29538l, 5408l}, { 3149l, 7400l}, { 9396l, 3058l}, {27149l, 20535l}, { 1777l, 8737l}, {26117l, 14251l}, { 7129l, 18195l}, {25302l, 10248l}};

printf("the ciphertext pairs (y1,y2) are:\n"); for (i = 0; i < 40; i++) { printf("(%5ld, %5ld) ", y[i].y1, y[i].y2); if ((i + 1) % 4 == 0) printf("\n"); } printf("the corresponding plaintext is:\n"); for (i = 0; i < 40; i++) { x = decrypt(a, p, y[i]); t = x / 676l; x = x % 676l; printf("%c", abc[t]); t = x / 26l; x = x % 26l; printf("%c", abc[t]); printf("%c", abc[x]); if ((i + 1) % 8 == 0) printf("\n"); } return 0;}

5.5 ex0505.txt (517)

Exercise"5.5 Determine which of the following polynomials areirreducible over Z_2[x]: x ^ 5 + x ^ 4 + 1,x ^ 5 + x ^ 3 + 1, x ^ 5 + x ^ 4 + x ^ 2 + 1."-Douglas R. Stinson-See "Cryptography: Theory and Practice" by Douglas R.Stinson pages 200-201.

x ^ 5 + x ^ 4 + 1 = (x ^ 2 + x + 1) * (x ^ 3 + x + 1) mod 2hence, it is not irreducible over Z_2[x]

x ^ 5 + x ^ 3 + 1 is irreducible over Z_2[x]

x ^ 5 + x ^ 4 + x ^ 2 + 1 = (x + 1) * (x ^ 4 + x + 1) mod 2hence, it is not irreducible over Z_2[x]

5.6 ex0506.c (5,773)

/*

Page 72: Classical CryptoAlgorithms (Ch 01-12)

Author: Pate Williams (c) 1997

Exercise "5.6 The field GF(2 ^ 5) can be constructed as Z_2[x]/(x ^ 5 + x ^ 2 + 1). Perform the following computations in this field. (a) Compute (x ^ 4 + x ^ 2) * (x ^ 3 + x + 1). (b) Using the Extended Euclidean algorithm compute (x ^ 3 + x ^ 2) ^ - 1. (c) Using the square and multiply algorithm, compute x ^ 25." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 201.*/

#include <math.h>#include <stdio.h>

#define SIZE 32l

void poly_mul(long m, long n, long *a, long *b, long *c, long *p){ long ai, bj, i, j, k, sum;

*p = m + n; for (k = 0; k <= *p; k++) { sum = 0; for (i = 0; i <= k; i++) { j = k - i; if (i > m) ai = 0; else ai = a[i]; if (j > n) bj = 0; else bj = b[j]; sum += ai * bj; } c[k] = sum; }}

void poly_div(long m, long n, long *u, long *v, long *q, long *r, long *p, long *s){ long j, jk, k, nk, vn = v[n];

for (j = 0; j <= m; j++) r[j] = u[j]; if (m < n) { *p = 0, *s = m; q[0] = 0; } else { *p = m - n, *s = n - 1; for (k = *p; k >= 0; k--) { nk = n + k; q[k] = r[nk] * pow(vn, k); for (j = nk - 1; j >= 0; j--) { jk = j - k; if (jk >= 0) r[j] = vn * r[j] - r[nk] * v[j - k]; else

Page 73: Classical CryptoAlgorithms (Ch 01-12)

r[j] = vn * r[j]; } } while (*p > 0 && q[*p] == 0) *p = *p - 1; while (*s > 0 && r[*s] == 0) *s = *s - 1; }}

void poly_exp_mod(long degreeA, long degreem, long n, long modulus, long *A, long *m, long *s, long *ds){ int zero; long dp, dq, dx = degreeA, i; long p[SIZE], q[SIZE], x[SIZE];

*ds = 0, s[0] = 1; for (i = 0; i <= dx; i++) x[i] = A[i]; while (n > 0) { if ((n & 1) == 1) { /* s = (s * x) % m; */ poly_mul(*ds, dx, s, x, p, &dp); poly_div(dp, degreem, p, m, q, s, &dq, ds); for (i = 0; i <= *ds; i++) s[i] %= modulus; zero = s[*ds] == 0, i = *ds; while (i > 0 && zero) { if (zero) *ds = *ds - 1; zero = s[--i] == 0; } } n >>= 1; /* x = (x * x) % m; */ poly_mul(dx, dx, x, x, p, &dp); poly_div(dp, degreem, p, m, q, x, &dq, &dx); for (i = 0; i <= dx; i++) x[i] %= modulus; zero = x[dx] == 0, i = dx; while (i > 0 && zero) { if (zero) dx--; zero = x[--i] == 0; } }}

void poly_copy(long db, long *a, long *b, long *da)/* a = b */{ long i;

*da = db; for (i = 0; i <= db; i++) a[i] = b[i];}

int poly_Extended_Euclidean(long db, long dn, long *b, long *n, long *t, long *dt){ int nonzero;

Page 74: Classical CryptoAlgorithms (Ch 01-12)

long db0, dn0, dq, dr, dt0 = 0, dtemp, du, i; long b0[SIZE], n0[SIZE], q[SIZE]; long r[SIZE], t0[SIZE], temp[SIZE], u[SIZE];

*dt = 0; poly_copy(dn, n0, n, &dn0); poly_copy(db, b0, b, &db0); t0[0] = 0; t[0] = 1; poly_div(dn0, db0, n0, b0, q, r, &dq, &dr); nonzero = r[0] != 0; for (i = 1; !nonzero && i <= dr; i++) nonzero = r[i] != 0; while (nonzero) { poly_mul(dq, *dt, q, t, u, &du); if (dt0 < du) for (i = dt0 + 1; i <= du; i++) t0[i] = 0; for (i = 0; i <= du; i++) temp[i] = t0[i] - u[i]; dtemp = du; poly_copy(*dt, t0, t, &dt0); poly_copy(dtemp, t, temp, dt); poly_copy(db0, n0, b0, &dn0); poly_copy(dr, b0, r, &db0); poly_div(dn0, db0, n0, b0, q, r, &dq, &dr); nonzero = r[0] != 0; for (i = 1; !nonzero && i <= dr; i++) nonzero = r[i] != 0; } if (db0 != 0 && b0[0] != 1) return 0; return 1;}

void poly_mod(long da, long p, long *a, long *new_da){ int zero; long i;

for (i = 0; i <= da; i++) { a[i] %= p; if (a[i] < 0) a[i] += p; } zero = a[da] == 0; for (i = da - 1; zero && i >= 0; i--) { da--; zero = a[i] == 0; } *new_da = da;}

void poly_write(char *label, long da, long *a){ long i;

printf("%s", label); for (i = da; i >= 0; i--) printf("%ld ", a[i]);

Page 75: Classical CryptoAlgorithms (Ch 01-12)

printf("\n");}

int main(void){ long da = 4, db = 3, dc = 3, dd = 5; long de, dq, dr, ds, p = 2; long a[5] = {0, 0, 1, 0, 1}; long b[4] = {1, 1, 0, 1}; long c[4] = {0, 0, 1, 1}; long d[6] = {1, 0, 1, 0, 0, 1}; long e[SIZE], q[SIZE], r[SIZE], s[SIZE];

poly_write("A = ", da, a); poly_write("B = ", db, b); poly_write("C = ", dc, c); poly_write("D = ", dd, d); poly_mul(da, db, a, b, e, &de); poly_mod(de, p, e, &de); poly_div(de, dd, e, d, q, r, &dq, &dr); poly_mod(dq, p, q, &dq); poly_mod(dr, p, r, &dr); poly_write("A * B mod 2 = ", de, e); poly_write("A * B / D mod 2 = ", dq, q); poly_write("A * B mod D, 2 = ", dr, r); if (!poly_Extended_Euclidean(dc, dd, c, d, e, &de)) printf("*error*\in poly_Extended_Euclidean\n"); poly_mod(de, p, e, &de); poly_write("C ^ - 1 mod D = ", de, e); poly_mul(dc, de, c, e, s, &ds); poly_mod(ds, p, s, &ds); poly_div(ds, dd, s, d, q, r, &dq, &dr); poly_mod(dr, p, r, &dr); poly_write("C * C ^ - 1 mod D, 2 = ", dr, r); dq = 1; q[0] = 0; q[1] = 1; poly_exp_mod(dq, dd, 7, p, q, d, s, &ds); poly_mod(ds, p, s, &ds); poly_write("x ^ 7 mod D, 2 = ", ds, s); poly_exp_mod(dq, dd, 9, p, q, d, s, &ds); poly_mod(ds, p, s, &ds); poly_write("x ^ 9 mod D, 2 = ", ds, s); poly_exp_mod(dq, dd, 10, p, q, d, s, &ds); poly_mod(ds, p, s, &ds); poly_write("x ^ 10 mod D, 2 = ", ds, s); poly_exp_mod(dq, dd, 25, p, q, d, s, &ds); poly_mod(ds, p, s, &ds); poly_write("x ^ 25 mod D, 2 = ", ds, s); return 0;}

5.7 ex0507.c (7,323)

/* Author: Pate Williams (c) 1997

Page 76: Classical CryptoAlgorithms (Ch 01-12)

Exercise "5.7 We give an example of ElGamal Cryptosystem implemented in GF(3 ^ 3). The polynomial x ^ 3 + 2x ^ 2 + 1 is irreducible over Z_3[x] and hence Z_3[x]/(x ^ 3 + 2x ^ 2 + 1) is the field GF(3 ^ 3). We can associate the 26 letters of the alphabet with the 26 nonzero field elements, and thus encrypt ordinary text in a convenient way. We will use the lexicographic ordering of the (nonzero) polynomials to set up the correspondence. The correspondence is as follows: A = 1, B = 2, C = x, D = x + 1, E = x + 2, F = 2x, G = 2x + 1, H = 2x + 2, I = x ^ 2, J = x ^ 2 + 1, K = x ^ 2 + 2, L = x ^ 2 + x, M = x ^ 2 + x + 1, N = x ^ 2 + x + 2, O = x ^ 2 + 2x, P = x ^ 2 + 2x + 1, Q = x ^ 2 + 2x + 2, R = 2x, S = 2x ^ 2 + 1, T = 2x ^ 2 + 2, U = 2x ^ x + x, V = 2x ^ 2 + x + 1, W = 2x ^ 2 + x + 2, X = 2x ^ 2 + 2x, Y = 2x ^ 2 + 2x + 1, Z = 2x ^ 2 + 2x + 2 Suppose Bob uses alpha = x and a = 11 in an ElGamal system; then beta = x + 2. Show how Bob will decrypt the following string of ciphertext: (K, H), (P, X), (N, K), (H, R), (T, F), (V, Y), (E, H), (F, A), (T, W), (J, D), (U, J)" -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 201.*/

#include <math.h>#include <stdio.h>#include <stdlib.h>

#define SIZE 32l

struct ciphertext {long y1, y2;};

void poly_mul(long m, long n, long *a, long *b, long *c, long *p){ long ai, bj, i, j, k, sum;

*p = m + n; for (k = 0; k <= *p; k++) { sum = 0; for (i = 0; i <= k; i++) { j = k - i; if (i > m) ai = 0; else ai = a[i]; if (j > n) bj = 0; else bj = b[j]; sum += ai * bj; } c[k] = sum; }

Page 77: Classical CryptoAlgorithms (Ch 01-12)

}

void poly_div(long m, long n, long *u, long *v, long *q, long *r, long *p, long *s){ long j, jk, k, nk, vn = v[n];

for (j = 0; j <= m; j++) r[j] = u[j]; if (m < n) { *p = 0, *s = m; q[0] = 0; } else { *p = m - n, *s = n - 1; for (k = *p; k >= 0; k--) { nk = n + k; if (k != 0) q[k] = r[nk] * pow(vn, k); else if (vn != 0) q[k] = r[nk]; else q[k] = 0; for (j = nk - 1; j >= 0; j--) { jk = j - k; if (jk >= 0) r[j] = vn * r[j] - r[nk] * v[j - k]; else r[j] = vn * r[j]; } } while (*p > 0 && q[*p] == 0) *p = *p - 1; while (*s > 0 && r[*s] == 0) *s = *s - 1; }}

void poly_copy(long db, long *a, long *b, long *da)/* a = b */{ long i;

*da = db; for (i = 0; i <= db; i++) a[i] = b[i];}

void poly_mod(long da, long p, long *a, long *new_da){ int zero; long i;

for (i = 0; i <= da; i++) { a[i] %= p; if (a[i] < 0) a[i] += p; } zero = a[da] == 0; for (i = da - 1; zero && i >= 0; i--) { da--; zero = a[i] == 0;

Page 78: Classical CryptoAlgorithms (Ch 01-12)

} *new_da = da;}

void poly_exp_mod(long degreeA, long degreem, long n, long modulus, long *A, long *m, long *s, long *ds){ long dp, dq, dx = degreeA, i; long p[SIZE], q[SIZE], x[SIZE];

*ds = 0, s[0] = 1; for (i = 0; i <= dx; i++) x[i] = A[i]; while (n > 0) { if ((n & 1) == 1) { /* s = (s * x) % m; */ poly_mul(*ds, dx, s, x, p, &dp); poly_mod(dp, modulus, p, &dp); poly_div(dp, degreem, p, m, q, s, &dq, ds); poly_mod(*ds, modulus, s, ds); } n >>= 1; /* x = (x * x) % m; */ poly_mul(dx, dx, x, x, p, &dp); poly_mod(dp, modulus, p, &dp); poly_div(dp, degreem, p, m, q, x, &dq, &dx); poly_mod(dx, modulus, x, &dx); }}

void poly_write(char *label, long da, long *a){ long i;

printf("%s", label); for (i = da; i >= 0; i--) printf("%ld ", a[i]); printf("\n");}

int poly_Extended_Euclidean(long db, long dn, long *b, long *n, long *t, long *dt){ int count = 0, nonzero; long db0, dn0, dq, dr, dt0 = 0, dtemp, du, i; long b0[SIZE], n0[SIZE], q[SIZE]; long r[SIZE], t0[SIZE], temp[SIZE], u[SIZE];

*dt = 0; poly_copy(dn, n0, n, &dn0); poly_copy(db, b0, b, &db0); t0[0] = 0; t[0] = 1; poly_div(dn0, db0, n0, b0, q, r, &dq, &dr); nonzero = r[0] != 0; for (i = 1; !nonzero && i <= dr; i++)

Page 79: Classical CryptoAlgorithms (Ch 01-12)

nonzero = r[i] != 0; while (nonzero && count++ < 8) { poly_mul(dq, *dt, q, t, u, &du); if (dt0 < du) for (i = dt0 + 1; i <= du; i++) t0[i] = 0; for (i = 0; i <= du; i++) temp[i] = t0[i] - u[i]; dtemp = du; poly_copy(*dt, t0, t, &dt0); poly_copy(dtemp, t, temp, dt); poly_copy(db0, n0, b0, &dn0); poly_copy(dr, b0, r, &db0); if (dn0 - db0 > 0) poly_div(dn0, db0, n0, b0, q, r, &dq, &dr); else return db0 == 0 && b[0] == 1; nonzero = r[0] != 0; for (i = 1; !nonzero && i <= dr; i++) nonzero = r[i] != 0; if (db0 == 0) return 1; } return 0;}

int main(void){ char message[4] = "A "; int found, plaintext; long a = 11, dm = 3, dy1, dy2, i, j, k; long dq, dr, dx, dy, dz; long p = 3, m[SIZE] = {1, 0, 2, 1}; long q[SIZE], r[SIZE], y1[SIZE], y2[SIZE]; long x[SIZE], y[SIZE], z[SIZE]; long field[26][4] = {{1, 0, 0, 0}, {2, 0, 0, 0}, {0, 1, 0, 0}, {1, 1, 0, 0}, {2, 1, 0, 0}, {0, 2, 0, 0}, {1, 2, 0, 0}, {2, 2, 0, 0}, {0, 0, 1, 0}, {1, 0, 1, 0}, {2, 0, 1, 0}, {0, 1, 1, 0}, {1, 1, 1, 0}, {2, 1, 1, 0}, {0, 2, 1, 0}, {1, 2, 1, 0}, {2, 2, 1, 0}, {0, 0, 2, 0}, {1, 0, 2, 0}, {2, 0, 2, 0}, {0, 1, 2, 0}, {1, 1, 2, 0}, {2, 1, 2, 0}, {0, 2, 2, 0}, {1, 2, 2, 0}, {2, 2, 2, 0}}; struct ciphertext c[11] = {{'K', 'H'}, {'P', 'X'}, {'N', 'K'}, {'H', 'R'}, {'T', 'F'}, {'V', 'Y'}, {'E', 'H'}, {'F', 'A'}, {'T', 'W'}, {'J', 'D'}, {'U', 'J'}};

for (i = 0; i < 26; i++) { message[0] = (char) (i + 'A'); poly_write(message, 2, field[i]); }

Page 80: Classical CryptoAlgorithms (Ch 01-12)

for (i = 0; i < 11; i++) { printf("(%c, %c) ", c[i].y1, c[i].y2); if ((i + 1) % 5 == 0) printf("\n"); } printf("\n"); for (i = 0; i < 11; i++) { poly_copy(2, y1, field[c[i].y1 - 'A'], &dy1); poly_copy(2, y2, field[c[i].y2 - 'A'], &dy2); poly_mod(dy1, p, y1, &dy1); poly_mod(dy2, p, y2, &dy2); poly_exp_mod(dy1, dm, a, p, y1, m, x, &dx); poly_Extended_Euclidean(dx, dm, x, m, y, &dy); poly_mod(dy, p, y, &dy); poly_mul(dy2, dy, y2, y, z, &dz); poly_mod(dz, p, z, &dz); poly_div(dz, dm, z, m, q, r, &dq, &dr); poly_mod(dr, p, r, &dr); found = 0; for (j = 0; !found && j < 26; j++) { found = r[0] == field[j][0]; for (k = 1; found && k <= dr; k++) found = r[k] == field[j][k]; if (found) plaintext = 'A' + j; } printf("%c", plaintext); } printf("\n"); return 0;}

5.8 ex0508.c (4,813)

/* Author: Pate Williams (c) 1997

Exercise "5.8 Let E be the elliptic curve y ^ 2 = x ^ 3 + x + 28 defined over Z_71. (a) Determine the number of points on E. (b) Show that E is not a cyclic group. (c) What is the maximum order of an element in E? Find an element having this order." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 201.*/

#include <math.h>#include <stdio.h>#include <stdlib.h>

#define MAX_POINTS 142l

struct point {long x, y;};

int JACOBI(long a, long n)

Page 81: Classical CryptoAlgorithms (Ch 01-12)

{ 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 = + 1; else if (m == 3 || m == 5) s = - 1; if (n % 4 == 3 && a1 % 4 == 3) s = - s; if (a1 != 1) n1 = n % a1; else n1 = 1; return s * JACOBI(n1, a1);}

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

if (b == 0) return 1; while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } if (a < 0) a += n; return a;}

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

long E_points(long a, long b, long p, struct point *e)/* returns the number of points on the elliptic

Page 82: Classical CryptoAlgorithms (Ch 01-12)

curve y ^ 2 = x ^ 3 + ax + b mod p */{ long count = 0, m = (p + 1) / 4, x, y;

if (p % 4 == 3) { for (x = 0; x < p; x++) { y = x * x * x + a * x + b; if (JACOBI(y, p) != - 1) { y = exp_mod(y, m, p); printf("(%2ld, %2ld) ", x, y); e[count].x = x; e[count].y = y; y = - y % p; if (y < 0) y += p; printf("(%2ld, %2ld) ", x, y); e[count + 1].x = x; e[count + 1].y = y; count += 2; if (count % 4 == 0) printf("\n"); } } if (count % 4 != 0) printf("\n"); } return count;}

void add(long a, long p, struct point P, struct point Q, struct point *R)/* elliptic curve point partial addition */{ long i, lambda;

if (P.x == Q.x && P.y == 0 && Q.y == 0) { R->x = 0; R->y = 1; return; } if (P.x == Q.x && P.y == p - Q.y) { R->x = 0; R->y = 1; return; } if (P.x == 0 && P.y == 1) { *R = Q; return; } if (Q.x == 0 && Q.y == 1) { *R = P; return; } if (P.x != Q.x) { i = Q.x - P.x; if (i < 0) i += p; i = Extended_Euclidean(i, p); lambda = ((Q.y - P.y) * i) % p; } else {

Page 83: Classical CryptoAlgorithms (Ch 01-12)

i = Extended_Euclidean((2 * P.y) % p, p); lambda = ((3 * P.x * P.x + a) * i) % p; } if (lambda < 0) lambda += p; R->x = (lambda * lambda - P.x - Q.x) % p; R->y = (lambda * (P.x - R->x) - P.y) % p; if (R->x < 0) R->x += p; if (R->y < 0) R->y += p;}

void multiply(long a, long k, long p, struct point P, struct point *R){ struct point S;

R->x = 0; R->y = 1; S = P; while (k != 0) { if (k & 1) add(a, p, *R, S, R); k >>= 1; if (k != 0) add(a, p, S, S, &S); }}

long order(long a, long p, struct point P){ long ord = 1; struct point Q = P, R;

do { ord++; add(a, p, P, Q, &R); Q = R; } while (R.x != 0 && R.y != 1); return ord;}

int main(void){ long a = 1, b = 28, h, i, p = 71; long max_order, min_order, noncyclic, ord; struct point e[MAX_POINTS], P, Q;

printf("E: y ^ 2 = x ^ 3 + %ld * x + %ld mod %ld\n", a, b, p); printf("the points (x, y) on E are:\n"); h = E_points(a, b, p, e) + 1; printf("the number of points on E is: %ld\n", h); max_order = 0; min_order = h; printf("the points (x, y) on E and their orders are:\n"); for (i = 0; i < h - 1; i++) { ord = order(a, p, e[i]); printf("(%2ld, %2ld) %2ld ", e[i].x, e[i].y, ord); if ((i + 1) % 3 == 0) printf("\n");

Page 84: Classical CryptoAlgorithms (Ch 01-12)

if (ord < h) noncyclic = 1; if (ord < min_order) { P = e[i]; min_order = ord; } if (ord > max_order) { Q = e[i]; max_order = ord; } } printf("\n"); if (noncyclic) printf("E is not a cyclic group\n"); printf("minimum order: %ld\n", min_order); printf("maximum order: %ld\n", max_order); printf("minimum (%2ld, %2ld)\n", P.x, P.y); printf("maximum (%2ld, %2ld)\n", Q.x, Q.y); return 0;}

5.9 ex0509.c (6,316)

/* Author: Pate Williams (c) 1997

Exercise "5.9 Let E be the elliptic curve y ^ 2 = x ^ 3 + x + 13 defined over Z_31. It can be shown that #E = 34 and (9, 10) is an element of order 34 in E. The Menezes-Vanstone Cryptosystem defined on E will have as its plaintext space Z_34* * Z_34*. Suppose Bob's secret exponent is a = 25. (a) Compute beta = a alpha. (b) Decrypt the following string of ciphertext: ((4, 9), 28, 7), ((19, 28), 9, 13), ((5, 22), 20, 17), ((25, 16), 12, 27). (c) Assuming that each plaintext represents two alphabetic characters, convert the plaintext into an English word. (Here we will use the correspondence A = 1,..., Z = 26, since 0 is not allowed in a (plaintext) ordered pair." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 201.*/

#include <math.h>#include <stdio.h>#include <stdlib.h>

#define MAX_POINTS 64l

struct point {long x, y;};struct ciphertext {struct point y0; long y1, y2;};

int JACOBI(long a, long n)

Page 85: Classical CryptoAlgorithms (Ch 01-12)

{ 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 = + 1; else if (m == 3 || m == 5) s = - 1; if (n % 4 == 3 && a1 % 4 == 3) s = - s; if (a1 != 1) n1 = n % a1; else n1 = 1; return s * JACOBI(n1, a1);}

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

if (b == 0) return 1; while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } if (a < 0) a += n; return a;}

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

long E_points(long a, long b, long p, struct point *e)/* returns the number of points on the elliptic

Page 86: Classical CryptoAlgorithms (Ch 01-12)

curve y ^ 2 = x ^ 3 + ax + b mod p */{ long count = 0, m = (p + 1) / 4, x, y;

if (p % 4 == 3) { for (x = 0; x < p; x++) { y = x * x * x + a * x + b; if (JACOBI(y, p) != - 1) { y = exp_mod(y, m, p); printf("(%2ld, %2ld) ", x, y); e[count].x = x; e[count].y = y; y = - y % p; if (y < 0) y += p; printf("(%2ld, %2ld) ", x, y); e[count + 1].x = x; e[count + 1].y = y; count += 2; if (count % 4 == 0) printf("\n"); } } if (count % 4 != 0) printf("\n"); } return count;}

void add(long a, long p, struct point P, struct point Q, struct point *R)/* elliptic curve point partial addition */{ long i, lambda;

if (P.x == Q.x && P.y == 0 && Q.y == 0) { R->x = 0; R->y = 1; return; } if (P.x == Q.x && P.y == p - Q.y) { R->x = 0; R->y = 1; return; } if (P.x == 0 && P.y == 1) { *R = Q; return; } if (Q.x == 0 && Q.y == 1) { *R = P; return; } if (P.x != Q.x) { i = Q.x - P.x; if (i < 0) i += p; i = Extended_Euclidean(i, p); lambda = ((Q.y - P.y) * i) % p; } else {

Page 87: Classical CryptoAlgorithms (Ch 01-12)

i = Extended_Euclidean((2 * P.y) % p, p); lambda = ((3 * P.x * P.x + a) * i) % p; } if (lambda < 0) lambda += p; R->x = (lambda * lambda - P.x - Q.x) % p; R->y = (lambda * (P.x - R->x) - P.y) % p; if (R->x < 0) R->x += p; if (R->y < 0) R->y += p;}

void multiply(long a, long k, long p, struct point P, struct point *R){ struct point S;

R->x = 0; R->y = 1; S = P; while (k != 0) { if (k & 1) add(a, p, *R, S, R); k >>= 1; if (k != 0) add(a, p, S, S, &S); }}

long order(long a, long p, struct point P){ long ord = 1; struct point Q = P, R;

do { ord++; add(a, p, P, Q, &R); Q = R; } while (R.x != 0 && R.y != 1); return ord;}

int main(void){ long A = 25, a = 1, b = 13, h, i, p = 31; long max_order, min_order, noncyclic, ord; long c1, c2, m1, m2; struct ciphertext c[4] ={{{4, 9}, 28, 7}, {{19, 28}, 9, 13}, {{5, 22}, 20, 17}, {{25, 16}, 12, 27}}; struct point alpha = {9, 10}, beta; struct point e[MAX_POINTS], P, Q;

printf("E: y ^ 2 = x ^ 3 + %ld * x + %ld mod %ld\n", a, b, p); printf("the the non-origin points (x, y) on E are:\n"); h = E_points(a, b, p, e) + 1; printf("the number of non-origin points on E is: %ld\n", h - 1); max_order = 0;

Page 88: Classical CryptoAlgorithms (Ch 01-12)

min_order = h + 1; printf("the non-origin points (x, y) on E "); printf("and their orders are:\n"); for (i = 0; i < h - 1; i++) { ord = order(a, p, e[i]); if (ord < h) noncyclic = 1; if (ord < min_order) { P = e[i]; min_order = ord; } if (ord > max_order) { Q = e[i]; max_order = ord; } printf("(%2ld, %2ld) %2ld ", e[i].x, e[i].y, ord); if ((i + 1) % 3 == 0) printf("\n"); } printf("\n"); if (noncyclic) printf("E is not a cyclic group\n"); printf("minimum order: %ld\n", min_order); printf("maximum order: %ld\n", max_order); printf("minimum (%2ld, %2ld)\n", P.x, P.y); printf("maximum (%2ld, %2ld)\n", Q.x, Q.y); printf("alpha = (%2ld, %2ld)\n", alpha.x, alpha.y); multiply(a, A, p, alpha, &beta); printf("beta = %ld alpha = (%2ld, %2ld)\n", A, beta.x, beta.y); printf("the ciphertext is:\n"); for (i = 0; i < 4; i++) printf("((%2ld, %2ld), %2ld, %2ld)\n", c[i].y0.x, c[i].y0.y, c[i].y1, c[i].y2); printf("the corresponding plaintext is:\n"); for (i = 0; i < 4; i++) { multiply(a, A, p, c[i].y0, &beta); c1 = beta.x; c2 = beta.y; m1 = (c[i].y1 * Extended_Euclidean(c1, p)) % p; m2 = (c[i].y2 * Extended_Euclidean(c2, p)) % p; printf("%c%c", m1 + 'A' - 1, m2 + 'A' - 1); } printf("\n"); return 0;}

5.10 ex0510.c (2,658)

/* Author: Pate Williams (c) 1997

Exercise "5.10 Suppose the Merkle-Hellman Cryptosystem has as its public list of sizes the vector t = (1394, 1256, 1508, 1987, 439, 650, 339, 2303, 810). Suppose Oscar discovers that p = 2503. (a) By trial and error, determine the value a

Page 89: Classical CryptoAlgorithms (Ch 01-12)

such that a ^ -1 t mod p is a permutation of a superincreasing list. (b) Show how the ciphertext 5746 would be decrypted." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson.*/

#include <stdio.h>#include <stdlib.h>

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

int superincreasing(long n, long *s){ long i, j, sum;

for (j = 0; j < n; j++) { sum = 0; for (i = 0; i < j; i++) sum += s[i]; if (s[j] <= sum) return 0; } return 1;}

int subset_sum(long T, long n, long *s, long *x){ long S = T, i, sum = 0;

for (i = n - 1; i >= 0; i--) { if (S >= s[i]) { S -= s[i]; x[i] = 1; } else x[i] = 0; } for (i = 0; i < n; i++) sum += x[i] * s[i];

Page 90: Classical CryptoAlgorithms (Ch 01-12)

return sum == T;}

int main(void){ int found = 0; long a, af, ai, i, j, n = 10, p = 2503, u, s[10]; long x[10], y = 5746, z; long t[10] = {1394, 1256, 1508, 1987, 439, 650, 724, 339, 2303, 810};

for (a = 1; !found && a < p; a++) { ai = Extended_Euclidean(a, p); for (i = 0; i < n; i++) s[i] = (ai * t[i]) % p; /* sort the sizes into ascending order */ for (i = 0; i < n - 1; i++) for (j = i + 1; j < n; j++) if (s[i] > s[j]) u = s[i], s[i] = s[j], s[j] = u; found = superincreasing(n, s); af = a; } printf("the public list of sizes is:\n"); for (i = 0; i < n; i++) printf("%4ld ", t[i]); printf("\n"); printf("a = %ld a ^ - 1 = %ld\n", af, ai); printf("the superincreasing size vector is:\n"); for (i = 0; i < n; i++) printf("%4ld ", s[i]); printf("\n"); z = (ai * y) % p; printf("z = (%ld * %ld) %% %ld = %ld\n", ai, y, p, z); if (subset_sum(z, n, s, x)) { printf("the solution vector is:\n"); for (i = 0; i < n; i++) printf("%ld ", x[i]); printf("\n"); } else printf("subset sum has no solution\n"); return 0;}

5.11 ex0511.c (4,425)

/* Author: Pate Williams (c) 1997

Exercise "5.11 It can be shown that the matrix H shown below is a parity-check matrix for a [15, 7, 5] code called a BCH code.

1 0 0 0 1 0 0 1 1 0 1 0 1 1 1

Page 91: Classical CryptoAlgorithms (Ch 01-12)

0 1 0 0 1 1 0 1 0 1 1 1 1 0 0 0 0 1 0 0 1 1 0 1 0 1 1 1 1 0 H = 0 0 0 1 0 0 1 1 0 1 0 1 1 1 1 1 0 0 0 1 1 0 0 0 1 1 0 0 0 1 0 0 0 1 1 0 0 0 1 1 0 0 0 1 1 0 0 1 0 1 0 0 1 0 1 0 0 1 0 1 0 1 1 1 1 0 1 1 1 1 0 1 1 1 1

Decode, if possible, each of the following received vectors r using the syndrome decoding method. (a) r = (1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0). (b) r = (1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0). (c) r = (1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0)." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 202.*/

#include <stdio.h>#include <stdlib.h>

#define MAX_ATTEMPTS 11025

void generate(long n, long w, long *e)/* generates an error vector of weight w */{ long i;

for (i = 0; i < n; i++) e[i] = 0; for (i = 0; i < w; i++) e[rand() % n] = 1;}

void mat_vec_mul(long k, long n, long *r, long *s, long **h){ long i, j, sum;

for (i = 0; i < k; i++) { sum = 0; for (j = 0; j < n; j++) sum += h[i][j] * r[j]; s[i] = sum % 2; }}

int syndrome(long d, long k, long n, long *e, long *r, long *s, long *x, long *y, long **h){ int equal, nonzero = 0; long i, j, l;

mat_vec_mul(k, n, r, s, h);

Page 92: Classical CryptoAlgorithms (Ch 01-12)

printf("the syndrome vector is:\n"); for (i = 0; i < k; i++) printf("%ld ", s[i]); printf("\n"); for (i = 0; !nonzero && i < k; i++) nonzero = s[i] != 0; if (!nonzero) { for (i = 0; i < n; i++) x[i] = r[i]; return 1; } /* generate and test all error vectors of weight 1 */ for (i = 0; i < n; i++) { for (j = 0; j < i; j++) e[j] = 0; e[i] = 1; for (j = i + 1; j < k; j++) e[j] = 0; mat_vec_mul(k, n, e, y, h); equal = 1; for (j = 0; equal && j < k; j++) equal = s[j] == y[j]; if (equal) { for (j = 0; j < n; j++) { x[j] = r[j] - e[j]; if (x[j] < 0) x[j] += 2; } return 1; } } for (i = 2; i <= d; i++) { for (j = 0; j < MAX_ATTEMPTS; j++) { generate(n, i, e); mat_vec_mul(k, n, e, y, h); equal = 1; for (l = 0; equal && l < k; l++) equal = s[l] == y[l]; if (equal) { for (l = 0; l < n; l++) { x[l] = r[l] - e[l]; if (x[l] < 0) x[l] += 2; } printf("the error vector is:\n"); for (l = 0; l < n; l++) printf("%ld ", e[l]); printf("\n"); return 1; } } } return 0;}

int main(void){ long H[8][15] = {{1,0,0,0,1,0,0,1,1,0,1,0,1,1,1}, {0,1,0,0,1,1,0,1,0,1,1,1,1,0,0}, {0,0,1,0,0,1,1,0,1,0,1,1,1,1,0}, {0,0,0,1,0,0,1,1,0,1,0,1,1,1,1}, {1,0,0,0,1,1,0,0,0,1,1,0,0,0,1},

Page 93: Classical CryptoAlgorithms (Ch 01-12)

{0,0,0,1,1,0,0,0,1,1,0,0,0,1,1}, {0,0,1,0,1,0,0,1,0,1,0,0,1,0,1}, {0,1,1,1,1,0,1,1,1,1,0,1,1,1,1}}; long r[3][15] = {{1,1,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,1,0,1,1,1,1,0,1,0,1,1,0,0,0}, {1,0,1,0,1,0,0,1,0,1,1,0,0,0,0}}; long d = 5, i, j, k = 7, n = 15; long e[15], s[15], x[15], y[15]; long **h = calloc(k + 1, sizeof(long *));

if (!h) { fprintf(stderr, "*error*\ninsufficient memory"); exit(1); } printf("the parity check matrix is:\n"); for (i = 0; i < k + 1; i++) { h[i] = calloc(n, sizeof(long *)); if (!h[i]) { fprintf(stderr, "*error*\ninsufficient memory"); exit(1); } for (j = 0; j < n; j++) { printf("%ld ", H[i][j]); h[i][j] = H[i][j]; } printf("\n"); } for (i = 0; i < 3; i++) { printf("the vector to be decoded is:\n"); for (j = 0; j < n; j++) printf("%ld ", r[i][j]); printf("\n"); if (syndrome(d, k + 1, n, e, r[i], s, x, y, h)) { printf("the decoded vector is:\n"); for (j = 0; j < n; j++) printf("%ld ", x[j]); printf("\n"); } else printf("vector was not decoded\n"); } for (i = 0; i < k + 1; i++) free(h[i]); free(h); return 0;}

Chapter 06 Signature Schemes

6.6 te0606.c (2,607)

6.1 ex0601.c (2,575)

Page 94: Classical CryptoAlgorithms (Ch 01-12)

6.2 ex0602.c freelip (3,317)

6.3 ex0603.c (2,173)

6.6 ex0606.c (1,995)

6.8 ex0608.c (3,176)

6.10 ex0610.c (2,902)

6.12 ex0612.c (722)

6.13 ex0613.c (2,546)

Example

6.6 te0606.c (2,607)

/* Author: Pate Williams (c) 1997

Example "6.6 As before, suppose p = 467, alpha = 4, a = 101 and beta = 449. Suppose the message x = 286 is signed with the (bogus) signature y = 83, and Bob wants to convince Alice that the signature is invalid." -Douglas R. Stinson- See "Cryptogrphy: Theory and Practice" by Douglas R. Stinson pages 222-223.*/

#include <stdio.h>

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; }

Page 95: Classical CryptoAlgorithms (Ch 01-12)

if (a < 0) a += n; return a;}

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

int main(void){ long a = 101, alpha = 4, beta = 449, e1 = 45; long e2 = 237, f1 = 125, f2 = 9, i, j, p = 467; long q, x = 286, y = 83, c, d, C, D, r, s, t;

q = (p - 1) >> 1; printf("a = %ld\n", a); printf("alpha = %ld\n", alpha); printf("beta = %ld\n", beta); printf("e1 = %ld\n", e1); printf("e2 = %ld\n", e2); printf("f1 = %ld\n", f1); printf("f2 = %ld\n", f2); printf("p = %ld\n", p); printf("q = %ld\n", q); printf("x = %ld\n", x); printf("y = %ld\n", y); i = Extended_Euclidean(a, q); c = (exp_mod(y, e1, p) * exp_mod(beta, e2, p)) % p; d = exp_mod(c, i, p); printf("Alice's challenge c = %ld\n", c); printf("Bob's response d = %ld\n", d); if (d != (exp_mod(x, e1, p) * exp_mod(alpha, e2, p)) % p) printf("d != x ^ e1 * alpha ^ e2 mod p\n"); else printf("d == x ^ e1 * alpha ^ e2 mod p\n"); C = (exp_mod(y, f1, p) * exp_mod(beta, f2, p)) % p; D = exp_mod(C, i, p); printf("Alice's challenge C = %ld\n", C); printf("Bob's response D = %ld\n", D); if (D != (exp_mod(x, f1, p) * exp_mod(alpha, f2, p)) % p)

Page 96: Classical CryptoAlgorithms (Ch 01-12)

printf("D != x ^ f1 * alpha ^ f2 mod p\n"); else printf("D == x ^ f1 * alpha ^ f2 mod p\n"); i = q - e2; if (i < 0) i += q; j = q - f2; if (j < 0) j += q; r = (d * exp_mod(alpha, i, p)) % p; s = exp_mod(r, f1, p); r = (D * exp_mod(alpha, j, p)) % p; t = exp_mod(r, e1, p); if (s == t) printf("Alice concludes y is a forgery\n"); else printf("Alice does not conclude y is a forgery\n"); return 0;}

Exercises

6.1 ex0601.c (2,575)

/* Author: Pate Williams (c) 1997

Exercise 6.1 "Suppose Bob is using the ElGamal Signature Scheme, and he signs two messages x1 and x2 with signatures (gamma_1, delta_1) and (gamma_2, delta_2), respectively. (The same value for gamma occurs in both signatures.) Suppose also that gcd(delta_1 - delta_2, p - 1) = 1. (c) Suppose p = 31847, alpha = 5 and beta = 25703. Perform the computations of k and a, given the signature (23972, 31396) for the message x = 8990 and the signature (23972, 20481) for the message x = 31415." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 231.*/

#include <math.h>#include <stdio.h>#include <stdlib.h>

struct data {long j, alpha_j;};struct signature {long gamma, delta;};

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) {

Page 97: Classical CryptoAlgorithms (Ch 01-12)

temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } return a;}

long gcd(long a, long b){ long r;

while (b != 0) r = a % b, a = b, b = r; return a;}

int main(void){ long A, B, a0; long a, alpha = 5, beta = 25703, p = 31847; long d, delta_p, epsilon, i, k, xp; long gamma, p1 = p - 1, x1 = 8990, x2 = 31415; struct signature s1 = {23972, 31396}; struct signature s2 = {23972, 20481};

delta_p = s1.delta - s2.delta; if (delta_p < 0) delta_p += p1; xp = x1 - x2; if (xp < 0) xp += p1; epsilon = Extended_Euclidean(delta_p, p1); k = (xp * epsilon) % p1; if (k < 0) k += p1; gamma = exp_mod(alpha, k, p); d = gcd(gamma, p1); A = gamma / d; B = (x1 - (k * s1.delta) % p1) / d; p1 /= d;

Page 98: Classical CryptoAlgorithms (Ch 01-12)

if (B < 0) B += p1; a0 = (Extended_Euclidean(A, p1) * B) % p1; for (i = 0; i < d; i++) { a = a0 + i * p1; if (beta == exp_mod(alpha, a, p)) break; } printf("gcd(delta_1 - delta_2, p - 1) = %ld\n", d); printf("(x1 - x2) mod (p - 1) = %ld\n", xp); printf("epsilon = %ld\n", epsilon); printf("gamma = %ld\n", gamma); printf("d = %ld\n", d); printf("k = %ld\n", k); printf("a = %ld\n", a); return 0;}

6.2 ex0602.c freelip (3,317)

/* Author: Pate Williams (c) 1997

Exercise "6.2 Suppose I implement the ElGamal Signature Scheme with p = 31847, a = 5, and beta = 26379. Write a computer program does the following. (a) Verify the signature (20679, 11082) on the message x = 20543. (b) Determine my secret exponent, a, using Shanks time-memory tradeoff. Then determine the random value k used in signing the message x." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 231.*/

#include <math.h>#include <stdio.h>#include <stdlib.h>

#define MAX_COUNT 256l

struct data {long j, alpha_j;};struct factor {long expon, prime;};

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } if (a < 0) a += n; return a;

Page 99: Classical CryptoAlgorithms (Ch 01-12)

}

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

int fcmp(const void *d1, const void *d2){ struct data *data1 = (struct data *) d1; struct data *data2 = (struct data *) d2;

if (data1->alpha_j < data2->alpha_j) return - 1; if (data1->alpha_j > data2->alpha_j) return + 1; return 0;}

long Shanks(long alpha, long beta, long p)/* returns log(alpha, beta) in Z_p where alpha is a generator and beta is in Z_p */{ long a, alpha_i, i, log, m = ceil(sqrt(p - 1)); struct data *table1 = calloc(m, sizeof(struct data)); struct data *table2 = calloc(m, sizeof(struct data)); struct data *d, key;

if (!table1 || !table2) { fprintf(stderr, "*error*\nin sufficient memory\n"); fprintf(stderr, "from Shanks\n"); exit(1); } /* create a logarithm table */ alpha_i = exp_mod(alpha, m, p); for (i = 0; i < m; i++) { table1[i].j = i; table1[i].alpha_j = exp_mod(alpha_i, i, p); } alpha_i = Extended_Euclidean(alpha, p); if ((alpha_i * alpha) % p != 1) { fprintf(stderr, "*error*\nin Extended_Euclidean\n"); exit(1);

Page 100: Classical CryptoAlgorithms (Ch 01-12)

} for (i = 0; i < m; i++) { table2[i].j = i; a = exp_mod(alpha_i, i, p); table2[i].alpha_j = (beta * a) % p; } /* sort the tables by second data item */ qsort(table1, m, sizeof(struct data), fcmp); qsort(table2, m, sizeof(struct data), fcmp); for (i = 0; i < m; i++) { key.j = table1[i].j; key.alpha_j = table1[i].alpha_j; d = bsearch(&key, table2, m, sizeof(struct data), fcmp); if (d) { log = (key.j * m + d->j) % (p - 1); if (exp_mod(alpha, log, p) == beta) return log; } } return 0;}

int main(void){ long alpha = 5, beta = 26379, gamma = 20679; long a, delta = 11082, k, p = 31847; long p1 = p - 1, x = 20543, y, z;

y = exp_mod(beta, gamma, p); z = exp_mod(gamma, delta, p); y = (y * z) % p; if (y == exp_mod(alpha, x, p)) printf("signature accepted\n"); else printf("signature rejected\n"); a = Shanks(alpha, beta, p); k = Shanks(alpha, gamma, p); printf("a = %ld\n", a); printf("k = %ld\n", k); y = Extended_Euclidean(k, p1); z = ((((x - a * gamma) % p1) * y) % p1) % p1; if (z < 0) z += p1; if (z != delta) printf("error in a, k calculations\n"); return 0;}

6.3 ex0603.c (2,173)

/* Author: Pate Williams (c) 1997

Exercise "6.3 Suppose Bob is using the ElGamal Signature Scheme as implemented in Example 6.1; p = 467, alpha = 2, and beta = 132. Suppose Bob has signed the message x = 100 with the signature (29, 51).

Page 101: Classical CryptoAlgorithms (Ch 01-12)

Compute the forged signature that Oscar can then form using h = 102, i = 45, and j = 293. Check that the resulting signature satisfies the verification condition." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 23l.*/

#include <stdio.h>

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } return a;}

int main(void){ long alpha = 2, beta = 132, h = 102, i = 45; long j = 293, p = 467, p1 = p - 1, x = 100; long gamma = 29, delta = 51; long lambda, mu, xp, r, s, t;

r = exp_mod(gamma, h, p); s = exp_mod(alpha, i, p); t = exp_mod(beta, j, p); lambda = (r * s * t) % p; r = (h * gamma - j * delta) % p1; if (r < 0) r += p1;

Page 102: Classical CryptoAlgorithms (Ch 01-12)

s = Extended_Euclidean(r, p1); mu = (delta * lambda * s) % p1; xp = (lambda * ((h * x + i * delta) % p1) * s) % p1; s = exp_mod(beta, lambda, p); t = exp_mod(lambda, mu, p); printf("alpha = %ld\n", alpha); printf("beta = %ld\n", beta); printf("gamma = %ld\n", gamma); printf("delta = %ld\n", delta); printf("p = %ld\n", p); printf("x = %ld\n", x); printf("lambda = %ld\n", lambda); printf("mu = %ld\n", mu); printf("x' = %ld\n", xp); if ((s * t) % p == exp_mod(alpha, xp, p)) printf("forgery verified\n"); else printf("forgery rejected\n"); return 0;}

6.6 ex0606.c (1,995)

/* Author: Pate Williams (c) 1997

Exercise "6.6 Suppose Bob uses the DSS with q = 101, p = 7879, alpha = 170, a = 75, and beta = 4567, as in Example 6.3. Determine Bob's signature on the message x = 5001 using the random value k = 49, and show how the resulting signature is verified." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 231.*/

#include <stdio.h>

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; }

Page 103: Classical CryptoAlgorithms (Ch 01-12)

if (b0 != 1) return 0; else return t % n;}

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } return a;}

int main(void){ long a = 75, alpha = 170, beta = 4567, k = 49; long p = 7879, q = 101, x = 5001; long delta, e1, e2, gamma, r, s, t;

gamma = exp_mod(alpha, k, p) % q; r = Extended_Euclidean(k, q); delta = ((x + (a * gamma) % q) * r) % q; r = Extended_Euclidean(delta, q); e1 = (x * r) % q; e2 = (gamma * r) % q; r = exp_mod(alpha, e1, p); s = exp_mod(beta, e2, p); t = ((r * s) % p) % q; printf("a = %ld\n", a); printf("k = %ld\n", k); printf("p = %ld\n", p); printf("q = %ld\n", q); printf("x = %ld\n", x); printf("alpha = %ld\n", alpha); printf("beta = %ld\n", beta); printf("delta = %ld\n", delta); printf("gamma = %ld\n", gamma); printf("e1 = %ld\n", e1); printf("e2 = %ld\n", e2); printf("ver = %ld\n", t); if (t == gamma) printf("signature accepted\n"); else printf("signature rejected\n"); return 0;}

6.8 ex0608.c (3,176)

/* Author: Pate Williams (c) 1997

Page 104: Classical CryptoAlgorithms (Ch 01-12)

Exercise "6.8 In the Bos-Chaum Scheme with k = 6 and n = 4, suppose that the messages x = (0, 1, 0, 0, 1, 1) and x' = (1, 1, 0, 1, 1, 1) are signed. Determine the new messages that can be signed by Oscar knowing the signatures of x and x'." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 231.*/

#include <math.h>#include <stdio.h>

#define SIZE 10

long factorial(long n)/* computes n factorial = n! */{ long f = 1, i;

for (i = 2; i <= n; i++) f *= i; return f;}

long binomial(long n, long m)/* computes the binomial coefficient B(n, m) */{ return factorial(n) / (factorial(n - m) * factorial(m));}

void Bos_Chaum(long n, long x, long *phi, long *count){ long b, e = n, t = n << 1;

*count = 0; while (t > 0) { t = t - 1; b = binomial(t, e); if (x > b) { x -= b; e--; phi[*count] = t + 1; *count = *count + 1; } }}

long Horner(long n, long *x){ long i, s = x[n - 1];

for (i = n - 2; i >= 0; i--) s = 2 * s + x[i]; return s;}

Page 105: Classical CryptoAlgorithms (Ch 01-12)

void construct(long count, long k, long n, long *phi, long *x, long *X){ int equal; long i, j, max = pow(2, k), y; long p_count, phip[SIZE];

for (i = 0; i < max; i++) { Bos_Chaum(n, i, phip, &p_count); if (count == p_count) { equal = phi[0] == phip[0]; for (j = 1; equal && j < count; j++) equal = phi[j] == phip[j]; if (equal) { y = *X = i; for (j = 0; j < k; j++) { x[j] = y & 1; y >>= 1; } return; } } } *X = 0;}

int main(void){ long i, k = 6, n = 4, r, s; long u_count, v_count; long x_count = 3, y_count = 4; long u[SIZE] = {0, 1, 0, 0, 1, 1}; long v[SIZE] = {1, 1, 0, 1, 1, 1}; long x[SIZE], y[SIZE]; long u_phi[SIZE], v_phi[SIZE]; long x_phi[SIZE] = {8, 6, 4}; long y_phi[SIZE] = {8, 7, 4, 2};

r = Horner(k, u); s = Horner(k, v); Bos_Chaum(n, r, u_phi, &u_count); Bos_Chaum(n, s, v_phi, &v_count); printf("the original messages are:\n"); printf("x = %ld = ", r); for (i = 0; i < k; i++) printf("%ld ", u[i]); printf("\nx' = %ld = ", s); for (i = 0; i < k; i++) printf("%ld ", v[i]); printf("\np = "); for (i = 0; i < u_count; i++) printf("%ld ", u_phi[i]); printf("\np' = "); for (i = 0; i < v_count; i++) printf("%ld ", v_phi[i]); construct(x_count, k, n, x_phi, x, &r);

Page 106: Classical CryptoAlgorithms (Ch 01-12)

construct(y_count, k, n, y_phi, y, &s); r = Horner(k, x); s = Horner(k, y); Bos_Chaum(n, r, x_phi, &x_count); Bos_Chaum(n, s, y_phi, &y_count); printf("\nthe new messages are:\n"); printf("x = %ld = ", r); for (i = 0; i < k; i++) printf("%ld ", x[i]); printf("\nx' = %ld = ", s); for (i = 0; i < k; i++) printf("%ld ", y[i]); printf("\np = "); for (i = 0; i < x_count; i++) printf("%ld ", x_phi[i]); printf("\np' = "); for (i = 0; i < y_count; i++) printf("%ld ", y_phi[i]); return 0;}

6.10 ex0610.c (2,902)

/* Author: Pate Williams (c) 1997

Exercise "6.10 Suppose Bob is using the Chaum-van Antwerpen Undenible Signature Scheme as in Example 6.5. That is, p = 467, alpha = 4, a = 101 and beta = 449. Suppose Bob is presented with the signature y = 25 on the message x = 157 and he wishes to prove it is a forgery. Suppose Alice's random numbers are e1 = 46, e2 = 123, f1 = 198, and f2 = 11 in the disavowel protocol. Compute Alice's challenges, c and d, and Bob responses, C and D, and show that Alice's consistency check will succeed." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 232.*/

#include <stdio.h>

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } if (a < 0) a += n; return a;

Page 107: Classical CryptoAlgorithms (Ch 01-12)

}

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

int main(void){ long a = 101, alpha = 4, beta = 449, e1 = 46; long e2 = 123, f1 = 198, f2 = 11, i, j, p = 467; long q, x = 157, y = 25, c, d, C, D, r, s, t;

q = (p - 1) >> 1; printf("a = %ld\n", a); printf("alpha = %ld\n", alpha); printf("beta = %ld\n", beta); printf("e1 = %ld\n", e1); printf("e2 = %ld\n", e2); printf("f1 = %ld\n", f1); printf("f2 = %ld\n", f2); printf("p = %ld\n", p); printf("q = %ld\n", q); printf("x = %ld\n", x); printf("y = %ld\n", y); i = Extended_Euclidean(a, q); c = (exp_mod(y, e1, p) * exp_mod(beta, e2, p)) % p; d = exp_mod(c, i, p); printf("Alice's challenge c = %ld\n", c); printf("Bob's response d = %ld\n", d); if (d != (exp_mod(x, e1, p) * exp_mod(alpha, e2, p)) % p) printf("d != x ^ e1 * alpha ^ e2 mod p\n"); else printf("d == x ^ e1 * alpha ^ e2 mod p\n"); C = (exp_mod(y, f1, p) * exp_mod(beta, f2, p)) % p; D = exp_mod(C, i, p); printf("Alice's challenge C = %ld\n", C); printf("Bob's response D = %ld\n", D); if (D != (exp_mod(x, f1, p) * exp_mod(alpha, f2, p)) % p) printf("D != x ^ f1 * alpha ^ f2 mod p\n"); else

Page 108: Classical CryptoAlgorithms (Ch 01-12)

printf("D == x ^ f1 * alpha ^ f2 mod p\n"); i = q - e2; if (i < 0) i += q; j = q - f2; if (j < 0) j += q; r = (d * exp_mod(alpha, i, p)) % p; s = exp_mod(r, f1, p); r = (D * exp_mod(alpha, j, p)) % p; t = exp_mod(r, e1, p); if (s == t) printf("Alice concludes y is a forgery\n"); else printf("Alice does not conclude y is a forgery\n"); return 0;}

6.12 ex0612.c (722)

/* Author: Pate Williams (c) 1997

Exercise "6.12 Suppose Bob is using the Pedersen-van Heyst Fail-stop Signature scheme, where p = 3467, alpha = 4, a0 = 1567 and beta = 514 (of course, the value of a0 is not known to Bob). (a) Using the fact that a0 = 1567, determine all possible keys K = (gamma1, gamma2, a1, a2, b1, b2) such that sig(42) = (1118, 1449). (b) Suppose that sig(420 = (1118, 1449) and sig(969) = (899, 471). Without using the fact that a0 = 1567, determine the value of K (this shows that the scheme is a one-time scheme)." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 232.*/

6.13 ex0613.c (2,546)

/* Author: Pate Williams (c) 1997

Exercise "6.13 Suppose Bob is using the Pedersen-van Heyst Fail-stop Signature Scheme with p = 5087, alpha = 25, and beta = 1866. Suppose the key is K = (5065, 5076, 144, 874, 1873, 2345). Now suppose Bob finds the signature (2219, 458) has been forged on the message 4785. (a) Prove that this forgery satisfies the verification condition, so it is a valid

Page 109: Classical CryptoAlgorithms (Ch 01-12)

signature. (b) Show how Bob will compute the proof of forgery, a0, given this forged signature." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 232.*/

#include <stdio.h>

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } return a;}

int main(void){ long a0, a1 = 144, a2 = 874, b1 = 1873, b2 = 2345; long alpha = 25, beta = 1866, gamma1 = 5065; long gamma2 = 5076, p = 5087, q = (p - 1) >> 1; long r, s, x = 4785, y1 = 2219, y2 = 458, z1, z2;

r = (gamma1 * exp_mod(gamma2, x, p)) % p; s = (exp_mod(alpha, y1, p) * exp_mod(beta, y2, p)) % p; if (r == s) printf("signature accepted\n"); else printf("signature rejected\n");

Page 110: Classical CryptoAlgorithms (Ch 01-12)

z1 = (a1 + x * b1) % q; z2 = (a2 + x * b2) % q; if (z2 > y2) a0 = ((y1 - z1) * Extended_Euclidean(z2 - y2, q)) % q; else a0 = ((z1 - y1) * Extended_Euclidean(y2 - z2, q)) % q; if (a0 < 0) a0 += q; printf("alpha = %ld\n", alpha); printf("beta = %ld\n", beta); printf("p = %ld\n", p); printf("q = %ld\n", q); printf("gamma1 = %ld\n", gamma1); printf("gamma2 = %ld\n", gamma2); printf("a1 = %ld\n", a1); printf("a2 = %ld\n", a2); printf("b1 = %ld\n", b1); printf("b2 = %ld\n", b2); printf("x = %ld\n", x); printf("y1 = %ld\n", y1); printf("y2 = %ld\n", y2); printf("sig(%ld) = (%ld, %ld)\n", x, z1, z2); printf("a0 = %ld\n", a0); if (beta == exp_mod(alpha, a0, p)) printf("a0 verified\n"); else printf("a0 not verified\n"); return 0;}

Chapter 07 Hash Functions

7.3 ex0703.c (2,058)

7.4 ex0704.c freelip (1,776)

7.6 ex0706.c (1,760)

Exercises

7.3 ex0703.c (2,058)

/* Author: Pate Williams (c) 1997

Exercise "7.3 Suppose p = 15083, alpha = 154, beta = 2307 in the Chaum-van Heijst-Piftmann Hash Function. Given the collision

Page 111: Classical CryptoAlgorithms (Ch 01-12)

alpha ^ 7431 * beta ^ 5564 = alpha ^ 1459 * beta ^ 954 (mod p), compute log(alpha, beta)." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 257.*/

#include <stdio.h>

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } return a;}

long gcd(long a, long b){ long r;

while (b != 0) r = a % b, a = b, b = r; return a;}

int main(void){ long alpha = 154, beta = 2307, p = 15083; long x1 = 7431, x2 = 5564, x3 = 1459, x4 = 954; long d, log, p1 = p - 1, q = (p - 1) >> 1, x, y;

Page 112: Classical CryptoAlgorithms (Ch 01-12)

x = x4 - x2; if (x < 0) x += p1; d = gcd(x, p1); if (d == 1) { y = Extended_Euclidean(x, p1); log = ((x1 - x3) * y) % p1; } else if (d == 2) { x = x4 - x2; if (x < 0) x += q; y = Extended_Euclidean(x, q); x = (x1 - x3) * y; log = x % p1; if (beta != exp_mod(alpha, log, p)) log = (x + q) % p1; } if (beta != exp_mod(alpha, log, p)) printf("error in log calculation\n"); printf("alpha = %ld\n", alpha); printf("beta = %ld\n", beta); printf("p = %ld\n", p); printf("q = %ld\n", q); printf("x1 = %ld\n", x1); printf("x2 = %ld\n", x2); printf("x3 = %ld\n", x3); printf("x4 = %ld\n", x4); printf("d = %ld\n", d); printf("log = %ld\n", log); return 0;}

7.4 ex0704.c freelip (1,776)

/* Author: Pate Williams (c) 1997

Exercise "5.4 Suppose n = pq, where p and q are two (secret) distinct large primes such that p = 2p_1 + 1 and q = 2q_1 + 1, where p_1 and q_1 are prime. Suppose that alpha is an element of order 2p_1q_1 in Z_n* (this is the largest order of any element in Z_n*). Define a hash function h : {1,...,n * n} -> Z_n* by the rule h(x) = alpha ^ x mod n. Now suppose that n = 603241 and alpha = 11 are used to define a hash function of this type. Suppose we are given three collisions h(1294755) = h(80115359) = h(52738737). Use this information to factor n." -Douglas R. Stinson- See "Cryptogrpahy: Theory and Practice" by Douglas R. Stinson page 257.*/

#include <stdio.h>

Page 113: Classical CryptoAlgorithms (Ch 01-12)

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

if (b == 0) return 1; while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } return a;}

long gcd(long a, long b){ long r;

while (b > 0) r = a % b, a = b, b = r; return a;}

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

int main(void)

7.6 ex0706.c (1,760)

/* Author: Pate Williams (c) 1997

Exercise "7.6 Using the (original) expansion function for SHS, Equation 7.1, express each of X[16],..., X[79] in terms of X[0],..., X[15]. Now, for each pair

Page 114: Classical CryptoAlgorithms (Ch 01-12)

X[i], X[j] where 1 <= i < j <= 15, use a computer program to determine lambda(i, j), which denotes the number of X[k]'s (16 <= k <= 79) such that X[i] and X[j] both occur in the expression for X[k]. What is the range of values for lambda(i, j)?" -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson.*/

#include <stdio.h>

int main(void){ long i, j, k, max = 0, min = 80; long matrix[80][20] = {{0}}; long lambda[20][20] = {{0}};

printf("the X[0] to X[15] usage matrix is:\n"); for (i = 0; i <= 15; i++) matrix[i][i] = 1; for (i = 16; i <= 79; i++) { for (j = 0; j <= 15; j++) { matrix[i][j] ^= matrix[i - 3][j]; matrix[i][j] ^= matrix[i - 8][j]; matrix[i][j] ^= matrix[i - 14][j]; matrix[i][j] ^= matrix[i - 16][j]; } } for (i = 1; i <= 15; i++) for (j = i + 1; j <= 15; j++) for (k = 16; k <= 79; k++) if (matrix[k][i] == 1 && matrix[k][j] == 1) lambda[i][j]++; for (i = 16; i <= 79; i++) { printf("%2ld ", i); for (j = 0; j <= 15; j++) printf("%ld ", matrix[i][j]); printf("\n"); } printf("the lambda matrix is:\n"); for (i = 1; i <= 15; i++) { for (j = i + 1; j <= 15; j++) { printf("%ld ", lambda[i][j]); if (lambda[i][j] < min) min = lambda[i][j]; if (lambda[i][j] > max) max = lambda[i][j]; } printf("\n"); } printf("maximum lambda = %ld\n", max); printf("minimum lambda = %ld\n", min); return 0;}

Page 115: Classical CryptoAlgorithms (Ch 01-12)

Chapter 08 Key Distribution and Key Agreement

8.1 ex0801.c (6,278)

8.2 ex0802.c (7,137)

8.3 ex0803.c (1,182)

8.4 ex0804.c (1,440)

8.6 ex0806.c (2,929)

Exercises

8.1 ex0801.c (6,278)

/* Author: Pate Williams (c) 1997

Exercise 8.1 "Suppose the Blom Scheme with k = 1 is implemented with four users U, V, W, and X. Suppose that p = 7873, r_u = 2365, r_v = 6648, r_w = 1837, and r_x = 2186. The secret g polnomials are as follows: g_u(x) = 6018 + 6351x g_v(x) = 3749 + 7121x g_w(x) = 7061 + 7802x g_x(x) = 635 + 6828x (a) Compute the key for each pair of users, verifying that each pair of users obtains a common key (that is K_u,v = K_v,u, etc.). (b) Show that W and X together can compute K_u,v." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 281.*/

#include <math.h>#include <stdio.h>#include <stdlib.h>

#define SIZE 4

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

Page 116: Classical CryptoAlgorithms (Ch 01-12)

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

void Blom_Scheme(long k, long m, long p, long *r, long **g, long **K){ long i, j, l, s, t;

for (i = 0; i < m; i++) { for (j = i + 1; j < m; j++) { t = r[j]; s = g[i][k]; for (l = k - 1; l >= 0; l--) s = t * s + g[i][l]; K[i][j] = s % p; } } for (i = 0; i < m; i++) { for (j = 0; j < i; j++) { t = r[j]; s = g[i][k]; for (l = k - 1; l >= 0; l--) s = t * s + g[i][l]; s %= p; if (s != K[j][i]) { fprintf(stderr, "fatal error\nin key calculation\n"); exit(1); } K[i][j] = s; } }}

void gaussian_elimination(long n, long p, long *b, long *x, long **m){ int found; long *d = calloc(n, sizeof(long)), ck, dj; long i, j, k, l, sum, t;

if (!d) {

Page 117: Classical CryptoAlgorithms (Ch 01-12)

fprintf(stderr, "fatal error\ninsufficient memory\n"); fprintf(stderr, "from gaussian_elimination\n"); exit(1); } for (j = 0; j < n; j++) { found = 0, i = j; while (!found && i < n) { found = m[i][j] != 0; if (!found) i++; } if (!found) { fprintf(stderr, "fatal error\nnon-invertible matrix\n"); fprintf(stderr, "from gaussian_elimination\n"); for (k = 0; k < n; k++) { for (l = 0; l < n; l++) printf("%ld ", m[k][l]); printf("\n"); } exit(1); } if (i > j) { /* swap elements */ for (l = j; l < n; l++) t = m[i][l], m[i][l] = m[j][l], m[j][l] = t; t = b[i], b[i] = b[j], b[j] = t; } dj = d[j] = Extended_Euclidean(m[j][j], p); if (dj == 0) { fprintf(stderr, "fatal error\nnon-invertlible element\n"); fprintf(stderr, "from gaussian elimination"); fprintf(stderr, "element %ld mod %ld\n", m[j][j], p); exit(1); } for (k = j + 1; k < n; k++) { ck = (dj * m[k][j]) % p; for (l = j + 1; l < n; l++) { m[k][l] = (m[k][l] - (ck * m[j][l]) % p) % p; if (m[k][l] < 0) m[k][l] += p; } b[k] = (b[k] - (ck * b[j]) % p) % p; if (b[k] < 0) b[k] += p; } } for (i = n - 1; i >= 0; i--) { sum = 0; for (j = i + 1; j < n; j++) sum += (m[i][j] * x[j]) % p; if (sum < 0) sum += p; x[i] = (d[i] * ((b[i] - sum) % p)) % p; if (x[i] < 0) x[i] += p; }}

void print_matrix(long m, long n, long **matrix){ long i, j;

Page 118: Classical CryptoAlgorithms (Ch 01-12)

for (i = 0; i < m; i++) { for (j = 0; j < n; j++) printf("%4ld ", matrix[i][j]); printf("\n"); }}

int main(void){ long i, j, k = 1, m = 4, n = 3, p = 7873, s; long b[SIZE], c[SIZE], r[SIZE], x[SIZE]; long **a, **g, **h, **K; long A = 2537, B = 4128, C = 6701;

a = calloc(m, sizeof(long *)); g = calloc(m, sizeof(long *)); h = calloc(m, sizeof(long *)); K = calloc(m, sizeof(long *)); if (!a || !g || !h || !K) { fprintf(stderr, "fatal error\ninsufficient memory\n"); exit(1); } for (i = 0; i < m; i++) { a[i] = calloc(n, sizeof(long)); g[i] = calloc(k, sizeof(long)); h[i] = calloc(n, sizeof(long)); K[i] = calloc(m, sizeof(long)); if (!a[i] || !g[i] || !h[i] || !K[i]) { fprintf(stderr, "fatal error\ninsufficient memory\n"); exit(1); } }/* g[0][0] = 6018, g[0][1] = 6351; g[1][0] = 3749, g[1][1] = 7121; g[2][0] = 7601, g[2][1] = 7802; g[3][0] = 635, g[3][1] = 6828;*/ r[0] = 2365; r[1] = 6648; r[2] = 1837; r[3] = 2186; for (i = 0; i < m; i++) { g[i][0] = (A + (B * r[i]) % p) % p; g[i][1] = (B + (C * r[i]) % p) % p; } Blom_Scheme(k, m, p, r, g, K); printf("the g matrix is:\n"); print_matrix(m, k + 1, g); printf("the K matrix is:\n"); print_matrix(m, m, K); a[0][0] = 1; a[0][1] = r[2]; a[1][1] = 1; a[1][2] = r[2]; a[2][0] = 1; a[2][1] = r[3];

Page 119: Classical CryptoAlgorithms (Ch 01-12)

a[3][1] = 1; a[3][2] = r[3]; b[0] = g[2][0]; b[1] = g[2][1]; b[2] = g[3][0]; b[3] = g[3][1]; for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { s = 0; for (k = 0; k < m; k++) s += (a[k][i] * a[k][j]) % p; s %= p; h[i][j] = s; } } printf("the A matrix:\n"); print_matrix(m, n, a); printf("A_t * A:\n"); print_matrix(n, n, h); for (i = 0; i < n; i++) { s = 0; for (j = 0; j < m; j++) s += (a[j][i] * b[j]) % p; s %= p; c[i] = s; } gaussian_elimination(n, p, c, x, h); printf("a, b, c in program:\n"); printf("%ld\n", A); printf("%ld\n", B); printf("%ld\n", C); printf("a, b, c calculated:\n"); for (i = 0; i < n; i++) printf("%ld\n", x[i]); h[0][0] = (x[0] + (x[1] * r[0]) % p) % p; h[0][1] = (x[1] + (x[2] * r[0]) % p) % p; printf("g_u given and calculated:\n"); printf("%4ld %4ld\n", g[0][0], h[0][0]); printf("%4ld %4ld\n", g[0][1], h[0][1]); for (i = 0; i < m; i++) { free(a[i]); free(g[i]); free(h[i]); free(K[i]); } free(a); free(g); free(h); free(K); return 0;}

8.2 ex0802.c (7,137)

/* Author: Pate Williams (c) 1997

Page 120: Classical CryptoAlgorithms (Ch 01-12)

Exercise 8.2 "Suppose the Blom Scheme with k = 2 is implemented for a set of five users, U, V, W, X and Y. Suppose that p = 97, r_u = 14, r_v = 38, r_w = 93, r_x = 69, and r_y = 70. The secret g polnomials are as follows: g_u(x) = 15 + 15x + 2x^2 g_v(x) = 95 + 77x + 83x^2 g_w(x) = 88 + 32x + 18x^2 g_x(x) = 62 + 91x + 59x^2 g_y(x) = 10 + 82x + 52x^2 (a) Show how U and V will compute the key K_u,v = K_v,u. (b) Show how W, X, and Y together can compute K_u,v." -Douglas R. Stinson- (b) Show that W and X together can compute K_u,v." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson pages 281-282. The polynomial is: f(x, y) = a + b(x + y) + c(x^2 + y^2) + dxy + e(xy^2 + x^2y) + fx^2y^2 Any three users can collaborate to determine the coefficients of the polynomial by solving a nine by six system of overdetermined equations.*/

#include <math.h>#include <stdio.h>#include <stdlib.h>

#define SIZE 10

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

void Blom_Scheme(long k, long m, long p,

Page 121: Classical CryptoAlgorithms (Ch 01-12)

long *r, long **g, long **K){ long i, j, l, s, t;

for (i = 0; i < m; i++) { for (j = i + 1; j < m; j++) { t = r[j]; s = g[i][k]; for (l = k - 1; l >= 0; l--) s = t * s + g[i][l]; K[i][j] = s % p; } } for (i = 0; i < m; i++) { for (j = 0; j < i; j++) { t = r[j]; s = g[i][k]; for (l = k - 1; l >= 0; l--) s = t * s + g[i][l]; s %= p; if (s != K[j][i]) { fprintf(stderr, "fatal error\nin key calculation\n"); exit(1); } K[i][j] = s; } }}

void gaussian_elimination(long n, long p, long *b, long *x, long **m){ int found; long *d = calloc(n, sizeof(long)), ck, dj; long i, j, k, l, sum, t;

if (!d) { fprintf(stderr, "fatal error\ninsufficient memory\n"); fprintf(stderr, "from gaussian_elimination\n"); exit(1); } for (j = 0; j < n; j++) { found = 0, i = j; while (!found && i < n) { found = m[i][j] != 0; if (!found) i++; } if (!found) { fprintf(stderr, "fatal error\nnon-invertible matrix\n"); fprintf(stderr, "from gaussian_elimination\n"); for (k = 0; k < n; k++) { for (l = 0; l < n; l++) printf("%ld ", m[k][l]); printf("\n"); } exit(1);

Page 122: Classical CryptoAlgorithms (Ch 01-12)

} if (i > j) { /* swap elements */ for (l = j; l < n; l++) t = m[i][l], m[i][l] = m[j][l], m[j][l] = t; t = b[i], b[i] = b[j], b[j] = t; } dj = d[j] = Extended_Euclidean(m[j][j], p); if (dj == 0) { fprintf(stderr, "fatal error\nnon-invertlible element\n"); fprintf(stderr, "from gaussian elimination"); fprintf(stderr, "element %ld mod %ld\n", m[j][j], p); exit(1); } for (k = j + 1; k < n; k++) { ck = (dj * m[k][j]) % p; for (l = j + 1; l < n; l++) { m[k][l] = (m[k][l] - (ck * m[j][l]) % p) % p; if (m[k][l] < 0) m[k][l] += p; } b[k] = (b[k] - (ck * b[j]) % p) % p; if (b[k] < 0) b[k] += p; } } for (i = n - 1; i >= 0; i--) { sum = 0; for (j = i + 1; j < n; j++) sum += (m[i][j] * x[j]) % p; if (sum < 0) sum += p; x[i] = (d[i] * ((b[i] - sum) % p)) % p; if (x[i] < 0) x[i] += p; }}

void print_matrix(long m, long n, long **matrix){ long i, j;

for (i = 0; i < m; i++) { for (j = 0; j < n; j++) printf("%2ld ", matrix[i][j]); printf("\n"); }}

int main(void){ long i, j, k = 2, m = 9, l, mm = 5, n = 6, p = 97, s; long b[SIZE], c[SIZE], r[SIZE], x[SIZE]; long **a, **g, **h, **K;

a = calloc(m, sizeof(long *)); g = calloc(m, sizeof(long *)); h = calloc(m, sizeof(long *)); K = calloc(m, sizeof(long *)); if (!a || !g || !h || !K) { fprintf(stderr, "fatal error\ninsufficient memory\n");

Page 123: Classical CryptoAlgorithms (Ch 01-12)

exit(1); } for (i = 0; i < m; i++) { a[i] = calloc(n, sizeof(long)); g[i] = calloc(k + 1, sizeof(long)); h[i] = calloc(n, sizeof(long)); K[i] = calloc(m, sizeof(long)); if (!a[i] || !g[i] || !h[i] || !K[i]) { fprintf(stderr, "fatal error\ninsufficient memory\n"); exit(1); } } g[0][0] = 15, g[0][1] = 15, g[0][2] = 2; g[1][0] = 95, g[1][1] = 77, g[1][2] = 83; g[2][0] = 88, g[2][1] = 32, g[2][2] = 18; g[3][0] = 62, g[3][1] = 91, g[3][2] = 59; g[4][0] = 10, g[4][1] = 82, g[4][2] = 52; r[0] = 14; r[1] = 38; r[2] = 92; r[3] = 69; r[4] = 70; Blom_Scheme(k, mm, p, r, g, K); printf("the g matrix is:\n"); print_matrix(mm, k + 1, g); printf("the r vector is:\n"); for (i = 0; i < mm; i++) printf("%2ld ", r[i]); printf("\n"); printf("the K matrix is:\n"); print_matrix(mm, mm, K); a[0][0] = 1; a[0][1] = r[2]; a[0][2] = r[2] * r[2]; a[1][1] = 1; a[1][3] = r[2]; a[1][4] = r[2] * r[2]; a[2][2] = 1; a[2][4] = r[2]; a[2][5] = r[2] * r[2]; a[3][0] = 1; a[3][1] = r[3]; a[3][2] = r[3] * r[3]; a[4][1] = 1; a[4][3] = r[3]; a[4][4] = r[3] * r[3]; a[5][2] = 1; a[5][4] = r[3]; a[5][5] = r[3] * r[3]; a[6][0] = 1; a[6][1] = r[4]; a[6][2] = r[4] * r[4]; a[7][1] = 1; a[7][3] = r[4]; a[7][4] = r[4] * r[4]; a[8][2] = 1; a[8][4] = r[4];

Page 124: Classical CryptoAlgorithms (Ch 01-12)

a[8][5] = r[4] * r[4]; b[0] = g[2][0]; b[1] = g[2][1]; b[2] = g[2][2]; b[3] = g[3][0]; b[4] = g[3][1]; b[5] = g[3][2]; b[6] = g[4][0]; b[7] = g[4][1]; b[8] = g[4][2]; for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { s = 0; for (l = 0; l < m; l++) s += (a[l][i] * a[l][j]) % p; s %= p; h[i][j] = s; } } printf("the A matrix:\n"); print_matrix(m, n, a); printf("A_t * A:\n"); print_matrix(n, n, h); for (i = 0; i < n; i++) { s = 0; for (j = 0; j < m; j++) s += (a[j][i] * b[j]) % p; s %= p; c[i] = s; } gaussian_elimination(n, p, c, x, h); printf("a, b, c, d, e, f calculated:\n"); for (i = 0; i < n; i++) printf("%ld ", x[i]); printf("\n"); h[0][0] = x[0] + x[1] * r[0] + x[2] * r[0] * r[0]; h[0][1] = x[1] + x[3] * r[0] + x[4] * r[0] * r[0]; h[0][2] = x[2] + x[4] * r[0] + x[5] * r[0] * r[0]; printf("g_u given and calculated\n"); for (i = 0; i <= k; i++) printf("%2ld %2ld\n", g[0][i], h[0][i] % p); for (i = 0; i < m; i++) { free(a[i]); free(g[i]); free(h[i]); free(K[i]); } free(a); free(g); free(h); free(K); return 0;}

8.3 ex0803.c (1,182)

Page 125: Classical CryptoAlgorithms (Ch 01-12)

/* Author: Pate Williams (c) 1997

Exercise 8.3 "Suppose that U and V carry out the Diffie-Hellman Key Exchange with p = 27001 and alpha = 101. Suppose that U chooses a_u = 21768 and V chooses a_v = 9898. Show the computations performed by both U and V, and determine the key they will compute." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 282.*/

#include <stdio.h>

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } return a;}

int main(void){ long alpha = 101, p = 27001; long a_u = 21768, a_v = 9898, b_u, b_v; long k_vu, k_uv;

b_u = exp_mod(alpha, a_u, p); b_v = exp_mod(alpha, a_v, p); k_vu = exp_mod(b_u, a_v, p); k_uv = exp_mod(b_v, a_u, p); printf("alpha = %ld\n", alpha); printf("p = %ld\n", p); printf("a_u = %ld\n", a_u); printf("a_v = %ld\n", a_v); printf("b_u = %ld\n", b_u); printf("b_v = %ld\n", b_v); printf("K_v,u = %ld\n", k_vu); printf("K_u,v = %ld\n", k_uv); return 0;}

8.4 ex0804.c (1,440)

/* Author: Pate Williams (c) 1997

Exercise 8.4

Page 126: Classical CryptoAlgorithms (Ch 01-12)

"Suppose that U and V carry out the MTI Protocol where p = 30113 and alpha = 52. Suppose that U has a_u = 8642 and chooses r_u = 28654, and V has a_v = 24763 and chooses r_v = 12385. Show the computations performed by both U and V, and determine the key they will compute." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 282.*/

#include <stdio.h>

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } return a;}

int main(void){ long alpha = 52, p = 30113; long a_u = 8642, a_v = 24763; long r_u = 28654, r_v = 12385; long b_u, b_v, s_u, s_v, K_uv, K_vu;

b_u = exp_mod(alpha, a_u, p); b_v = exp_mod(alpha, a_v, p); s_u = exp_mod(alpha, r_u, p); s_v = exp_mod(alpha, r_v, p); K_uv = (exp_mod(s_v, a_u, p) * exp_mod(b_v, r_u, p)) % p; K_vu = (exp_mod(s_u, a_v, p) * exp_mod(b_u, r_v, p)) % p; printf("alpha = %ld\n", alpha); printf("p = %ld\n", p); printf("a_u = %ld\n", a_u); printf("a_v = %ld\n", a_v); printf("r_u = %ld\n", r_u); printf("r_v = %ld\n", r_v); printf("b_u = %ld\n", b_u); printf("b_v = %ld\n", b_v); printf("K_u,v = %ld\n", K_uv); printf("K_v,u = %ld\n", K_vu); return 0;}

8.6 ex0806.c (2,929)

/* Author: Pate Williams (c) 1997

Page 127: Classical CryptoAlgorithms (Ch 01-12)

Exercise 8.6 "Consider the Girault Scheme where p = 167, q = 179, and hence n = 29893. Suppose alpha = 2 and e = 11101. (a) Compute d. (b) Given ID(U) = 10021 and a_u = 9843, compute b_u and p_u. Given that ID(V) = 10022 and a_v = 7692, compute b_v and p_v. (c) Show how b_u can be computed from p_u and ID(U) using the public exponent e. Similarly, show how b_v can be computed from p_v and ID(V). (d) Suppose that U chooses r_u = 15556 and V chooses r_v = 6420. Compute s_u and s_v, and show how U and V each compute a common key." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 282.*/

#include <stdio.h>

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } return a;}

int main(void){

Page 128: Classical CryptoAlgorithms (Ch 01-12)

long alpha = 2, e = 11101, p = 167, q = 179; long a_u = 9843, a_v = 7692, c_u, c_v; long n = p * q, phi = (p - 1) * (q - 1); long d = Extended_Euclidean(e, phi); long ID_U = 10021, ID_V = 10022; long r_u = 15556, r_v = 6420; long b_u, b_v, p_u, p_v, s_u, s_v, K_uv, K_vu;

b_u = exp_mod(alpha, a_u, n); b_v = exp_mod(alpha, a_v, n); c_u = b_u - ID_U; if (c_u < 0) c_u += n; c_v = b_v - ID_V; if (c_v < 0) c_v += n; p_u = exp_mod(c_u, d, n); p_v = exp_mod(c_v, d, n); s_u = exp_mod(alpha, r_u, n); s_v = exp_mod(alpha, r_v, n); c_u = (exp_mod(p_v, e, n) + ID_V) % n; c_v = (exp_mod(p_u, e, n) + ID_U) % n; K_uv = (exp_mod(s_v, a_u, n) * exp_mod(c_u, r_u, n)) % n; K_vu = (exp_mod(s_u, a_v, n) * exp_mod(c_v, r_v, n)) % n; c_u = (exp_mod(p_u, e, n) + ID_U) % n; c_v = (exp_mod(p_v, e, n) + ID_V) % n; printf("alpha = %ld\n", alpha); printf("p = %ld\n", p); printf("q = %ld\n", q); printf("n = %ld\n", n); printf("a_u = %ld\n", a_u); printf("a_v = %ld\n", a_v); printf("ID(U) = %ld\n", ID_U); printf("ID(V) = %ld\n", ID_V); printf("r_u = %ld\n", r_u); printf("r_v = %ld\n", r_v); printf("e = %ld\n", e); printf("d = %ld\n", d); printf("b_u = %ld\n", b_u); printf("b_v = %ld\n", b_v); printf("p_u = %ld\n", p_u); printf("p_v = %ld\n", p_v); printf("b_u another way = %ld\n", c_u); printf("b_v another way = %ld\n", c_v); printf("K_uv = %ld\n", K_uv); printf("K_vu = %ld\n", K_vu); return 0;}

Chapter 09 Identifciation Schemes

9.2 ex0902.c freelip (1,891)

9.3 ex0903.c freelip (1,724)

Page 129: Classical CryptoAlgorithms (Ch 01-12)

9.4 ex0904.c freelip (2,591)

9.5 ex0905.c freelip (3,245)

9.6 ex0906.c freelip (1,716)

9.7 ex0907.c freelip (1,605)

Exercises

9.2 ex0902.c freelip (1,891)

/* Author: Pate Williams (c) 1997

Exercise 9.2 "Suppose Alice is using the Schnorr Scheme where q = 1201, p = 122503, t = 10, and alpha = 11538. (a) Verify that alpha has order q in Z_p*. (b) Suppose that Alice's secret exponent is a = 357. Compute v. (c) Suppose that k = 868. Compute gamma. (d) Suppose that Bob issues the challenge r = 501. Compute Alice's response y. (e) Perform Bob's calculations to verify y." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson pages 303-304.*/

#include <stdio.h>#include "lip.h"

int main(void){ long alpha = 11538, p = 122503, q = 1201; long a = 357, k = 868, r = 501; verylong za = 0, zb = 0, zc = 0, zk = 0, zp = 0; verylong zq = 0, zr = 0, zv = 0, zy = 0; verylong zalpha = 0, zgamma = 0;

zintoz(alpha, &zalpha); zintoz(a, &za); zintoz(k, &zk); zintoz(p, &zp); zintoz(q, &zq); zintoz(r, &zr); zexpmod(zalpha, zq, zp, &zb); printf("alpha = %ld\n", alpha);

Page 130: Classical CryptoAlgorithms (Ch 01-12)

printf("p = %ld\n", p); printf("q = %ld\n", q); printf("a = %ld\n", a); printf("k = %ld\n", k); printf("r = %ld\n", r); printf("alpha ^ q mod p = "); zwriteln(zb); zcopy(za, &zb); znegate(&zb); zadd(zb, zq, &zc); zexpmod(zalpha, zc, zp, &zv); printf("v = "); zwriteln(zv); zexpmod(zalpha, zk, zp, &zgamma); printf("gamma = "); zwriteln(zgamma); zmulmod(za, zr, zq, &zb); zaddmod(zk, zb, zq, &zy); printf("y = "); zwriteln(zy); zexpmod(zalpha, zy, zp, &zb); zexpmod(zv, zr, zp, &zc); zmulmod(zb, zc, zp, &za); if (zcompare(za, zgamma) == 0) printf("y verified\n"); else printf("y not verfied\n"); zfree(&za); zfree(&zb); zfree(&zc); zfree(&zk); zfree(&zp); zfree(&zq); zfree(&zr); zfree(&zy); zfree(&zalpha); zfree(&zgamma); return 0;}

9.3 ex0903.c freelip (1,724)

/* Author: Pate Williams (c) 1997

Exercise 9.3 "Suppose that Alice uses the Schnorr Scheme with p, q, t, and alpha as in Exercise 9.2. Now suppose that v = 51131, and Olga has learned that alpha ^ 3 v ^ 148 = alpha ^ 151 v ^ 1077 mod p. Show how Olga can compute Alice's secret exponent a." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 304.*/

Page 131: Classical CryptoAlgorithms (Ch 01-12)

#include <stdio.h>#include "lip.h"

int main(void){ long alpha = 11538, p = 122503, q = 1201; long r1 = 148, r2 = 1077, y1 = 3, y2 = 151; long v = 51131; verylong za = 0, zb = 0, zc = 0, zd = 0, zp = 0; verylong zq = 0, zv = 0; verylong zalpha = 0, zr1 = 0, zr2 = 0; verylong zy1 = 0, zy2 = 0;

zintoz(alpha, &zalpha); zintoz(p, &zp); zintoz(q, &zq); zintoz(v, &zv); zintoz(r1, &zr1); zintoz(r2, &zr2); zintoz(y1, &zy1); zintoz(y2, &zy2); zexpmod(zalpha, zq, zp, &zb); printf("alpha = %ld\n", alpha); printf("p = %ld\n", p); printf("q = %ld\n", q); printf("v = %ld\n", v); printf("r_1 = %ld\n", r1); printf("r_2 = %ld\n", r2); printf("y_1 = %ld\n", y1); printf("y_2 = %ld\n", y2); zsubmod(zy1, zy2, zq, &zb); zsubmod(zr1, zr2, zq, &zc); zinvmod(zc, zq, &zd); zmulmod(zb, zd, zq, &za); printf("a = "); zwriteln(za); zsub(zq, za, &zb); zexpmod(zalpha, zb, zp, &zc); if (zcompare(zc, zv) == 0) printf("private exponent verified\n"); else printf("private exponent not verified\n"); zfree(&za); zfree(&zb); zfree(&zc); zfree(&zd); zfree(&zp); zfree(&zq); zfree(&zv); zfree(&zalpha); zfree(&zr1); zfree(&zr2); zfree(&zy1); zfree(&zy2); return 0;}

Page 132: Classical CryptoAlgorithms (Ch 01-12)

9.4 ex0904.c freelip (2,591)

/* Author: Pate Williams (c) 1997

Exercise 9.4 "Suppose that Alice is using the Okamoto Scheme with q = 1201, p = 122503, t = 10, alpha_1 = 60497 and alpha_2 = 17163. (a) Suppose that Alice's secret exponents are a_1 = 432 and a_2 = 423. Compute v. (b) Suppose that k_1 = 389 and k_2 = 191. Compute gamma. (c) Suppose that Bob issues the challenge r = 21. Compute Alices's response y_1 and y_2. (d) Perform Bob's calculations to verify y_1 and y_2." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 304.*/

#include <stdio.h>#include "lip.h"

int main(void){ long alpha1 = 60497, alpha2 = 17163; long p = 122503, q = 1201, r = 21; long a1 = 432, a2 = 423, k1 = 389, k2 = 191; verylong za = 0, zb = 0, zc = 0, zd = 0; verylong zp = 0, zq = 0, zr = 0, zv = 0; verylong za1 = 0, za2 = 0, zk1 = 0, zk2 = 0; verylong zy1 = 0, zy2 = 0; verylong zalpha1 = 0, zalpha2 = 0, zgamma = 0;

zintoz(alpha1, &zalpha1); zintoz(alpha2, &zalpha2); zintoz(p, &zp); zintoz(q, &zq); zintoz(r, &zr); zintoz(a1, &za1); zintoz(a2, &za2); zintoz(k1, &zk1); zintoz(k2, &zk2); zsub(zq, za1, &za); zsub(zq, za2, &zb); zexpmod(zalpha1, za, zp, &zc); zexpmod(zalpha2, zb, zp, &zd); zmulmod(zc, zd, zp, &zv); zexpmod(zalpha1, zk1, zp, &za); zexpmod(zalpha2, zk2, zp, &zb); zmulmod(za, zb, zp, &zgamma); zmulmod(za1, zr, zq, &za); zaddmod(zk1, za, zq, &zy1); zmulmod(za2, zr, zq, &za); zaddmod(zk2, za, zq, &zy2);

Page 133: Classical CryptoAlgorithms (Ch 01-12)

zexpmod(zalpha1, zy1, zp, &za); zexpmod(zalpha2, zy2, zp, &zb); zexpmod(zv, zr, zp, &zc); zmulmod(za, zb, zp, &zd); zmulmod(zc, zd, zp, &za); printf("alpha_1 = %ld\n", alpha1); printf("alpha_2 = %ld\n", alpha2); printf("p = %ld\n", p); printf("q = %ld\n", q); printf("a_1 = %ld\n", a1); printf("a_2 = %ld\n", a2); printf("k_1 = %ld\n", k1); printf("k_2 = %ld\n", k2); printf("r = %ld\n", r); printf("v = "); zwriteln(zv); printf("gamma = "); zwriteln(zgamma); printf("y_1 = "); zwriteln(zy1); printf("y_2 = "); zwriteln(zy2); if (zcompare(zgamma, za) == 0) printf("y_1 and y_2 verified\n"); else printf("y_1 and y_2 not verified\n"); zfree(&za); zfree(&zb); zfree(&zc); zfree(&zd); zfree(&zp); zfree(&zq); zfree(&zr); zfree(&zv); zfree(&za1); zfree(&za2); zfree(&zk1); zfree(&zk2); zfree(&zy1); zfree(&zy2); zfree(&zalpha1); zfree(&zalpha2); zfree(&zgamma); return 0;}

9.5 ex0905.c freelip (3,245)

/* Author: Pate Williams (c) 1997

Exercise 9.5 "Suppose that Alice uses the Okamoto Scheme with p, q, t, alpha_1 and alpha_2 as in Exercise 9.4. Suppose also that v = 119504. (a) Verify that

Page 134: Classical CryptoAlgorithms (Ch 01-12)

alpha_1 ^ 70 alpha_2 ^ 1033 v ^ 877 = alpha_1 ^ 248 alpha_2 ^ 882 v ^ 992 mod p. (b) Use this information to compute b_1 and b_2 such that alpha_1 ^ - b_1 alpha_2 ^ - b_2 = v mod p. (c) Now suppose that Alice reveals that a_1 = 484 and a_2 = 935. Show how Alice and Olga together will compute log(alpha_1, alpha_2)." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 304.*/

#include <stdio.h>#include "lip.h"

int main(void){ long alpha1 = 60497, alpha2 = 17163; long p = 122503, q = 1201, r = 877, s = 992; long v = 119504; long a1 = 484, a2 = 935; long y1 = 70, y2 = 1033, z1 = 248, z2 = 883; verylong za = 0, zb = 0, zc = 0, zd = 0, ze = 0; verylong zf = 0, zp = 0, zq = 0, zr = 0, zs = 0; verylong zv = 0; verylong za1 = 0, za2 = 0, zb1 = 0, zb2 = 0; verylong zy1 = 0, zy2 = 0, zz1 = 0, zz2 = 0; verylong zalpha1 = 0, zalpha2 = 0;

zintoz(alpha1, &zalpha1); zintoz(alpha2, &zalpha2); zintoz(p, &zp); zintoz(q, &zq); zintoz(r, &zr); zintoz(s, &zs); zintoz(v, &zv); zintoz(a1, &za1); zintoz(a2, &za2); zintoz(y1, &zy1); zintoz(y2, &zy2); zintoz(z1, &zz1); zintoz(z2, &zz2); zexpmod(zalpha1, zy1, zp, &za); zexpmod(zalpha2, zy2, zp, &zb); zexpmod(zv, zr, zp, &zc); zmulmod(za, zb, zp, &zd); zmulmod(zc, zd, zp, &ze); zexpmod(zalpha1, zz1, zp, &za); zexpmod(zalpha2, zz2, zp, &zb); zexpmod(zv, zs, zp, &zc); zmulmod(za, zb, zp, &zd); zmulmod(zc, zd, zp, &zf); zsubmod(zy1, zz1, zq, &za); zsubmod(zr, zs, zq, &zb); zinvmod(zb, zq, &zc); zmulmod(za, zc, zq, &zb1);

Page 135: Classical CryptoAlgorithms (Ch 01-12)

zsubmod(zy2, zz2, zq, &za); zmulmod(za, zc, zq, &zb2); zsubmod(za1, zb1, zq, &za); zsubmod(zb2, za2, zq, &zb); zinvmod(zb, zq, &zd); zmulmod(za, zd, zq, &zc); zexpmod(zalpha1, zc, zp, &za); printf("alpha_1 = %ld\n", alpha1); printf("alpha_2 = %ld\n", alpha2); printf("p = %ld\n", p); printf("q = %ld\n", q); printf("r = %ld\n", r); printf("s = %ld\n", s); printf("v = %ld\n", v); printf("a_1 = %ld\n", a1); printf("a_2 = %ld\n", a2); printf("y_1 = %ld\n", y1); printf("y_2 = %ld\n", y2); printf("z_1 = %ld\n", z1); printf("z_2 = %ld\n", z2); if (zcompare(ze, zf) == 0) printf("equation verified\n"); else printf("equation not verified\n"); printf("b_1 = "); zwriteln(zb1); printf("b_2 = "); zwriteln(zb2); printf("log(alpha_1, alpha_2) = "); zwriteln(zc); if (zcompare(za, zalpha2) == 0) printf("log(alpha_1, alpha_2) verified\n"); else printf("log(alpha_1, alpha_2) not verified\n"); zfree(&za); zfree(&zb); zfree(&zc); zfree(&zd); zfree(&ze); zfree(&zf); zfree(&zp); zfree(&zq); zfree(&zr); zfree(&zs); zfree(&zv); zfree(&za1); zfree(&za2); zfree(&zb1); zfree(&zb2); zfree(&zy1); zfree(&zy2); zfree(&zz1); zfree(&zz2); zfree(&zalpha1); zfree(&zalpha2); return 0;}

Page 136: Classical CryptoAlgorithms (Ch 01-12)

9.6 ex0906.c freelip (1,716)

/* Author: Pate Williams (c) 1997

Exercise 9.6 "Suppose that Alice is using the Quisquater Scheme with p = 503, q = 379, and b = 509. (a) Suppose that Alice's secret u = 155863. Compute v. (b) Suppose that k = 123845. Compute gamma. (c) Suppose that Bob issues the challenge r = 487. Compute Alice's response y. (d) Perform Bob's calculation to verify y." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 304.*/

#include <stdio.h>#include "lip.h"

int main(void){ long b = 509, k = 123845, p = 503, q = 379; long n = p * q, r = 487, u = 155863; verylong za = 0, zb = 0, zc = 0, zd = 0, zk = 0; verylong zn = 0, zr = 0, zu = 0, zv = 0, zy = 0; verylong zgamma = 0;

zintoz(b, &zb); zintoz(k, &zk); zintoz(n, &zn); zintoz(r, &zr); zintoz(u, &zu); zexpmod(zk, zb, zn, &zgamma); zexpmod(zu, zr, zn, &za); zmulmod(za, zk, zn, &zy); zinvmod(zu, zn, &za); zexpmod(za, zb, zn, &zv); zexpmod(zv, zr, zn, &za); zexpmod(zy, zb, zn, &zc); zmulmod(za, zc, zn, &zd); printf("p = %ld\n", p); printf("q = %ld\n", q); printf("b = %ld\n", b); printf("n = %ld\n", n); printf("k = %ld\n", k); printf("r = %ld\n", r); printf("u = %ld\n", u); printf("v = "); zwriteln(zv); printf("gamma = "); zwriteln(zgamma); printf("y = "); zwriteln(zy);

Page 137: Classical CryptoAlgorithms (Ch 01-12)

if (zcompare(zd, zgamma) == 0) printf("Bob has verified y\n"); else printf("Bob did no verify y\n"); zfree(&za); zfree(&zb); zfree(&zc); zfree(&zd); zfree(&zk); zfree(&zn); zfree(&zr); zfree(&zu); zfree(&zv); zfree(&zy); zfree(&zgamma); return 0;}

9.7 ex0907.c freelip (1,605)

/* Author: Pate Williams (c) 1997

Exercise 9.7 "Suppose that Alice is using the Quisquater Scheme with n = 199543, b = 523, and v = 146152. Suppose that Olga has discovered that v ^ 465 101360 ^ b = v ^ 257 36056 ^ b mod n. Show how Olga can compute u." -Douglas R. Stinson- See "Cryptograhy: Theory and Practice" by Douglas R. Stinson page 304.*/

#include <stdio.h>#include "lip.h"

int main(void){ long b = 523, n = 199543l, v = 146152l; long r1 = 456, r2 = 257, y1 = 101360l; long y2 = 36056l; verylong za = 0, zb = 0, zc = 0, zd = 0, zl = 0; verylong zn = 0, zt = 0, zu = 0, zv = 0; verylong zr1 = 0, zr2 = 0, zy1 = 0, zy2 = 0;

zintoz(b, &zb); zintoz(n, &zn); zintoz(v, &zv); zintoz(r1, &zr1); zintoz(r2, &zr2); zintoz(y1, &zy1); zintoz(y2, &zy2); zsubmod(zr1, zr2, zb, &za); zinvmod(za, zb, &zt); zmul(za, zt, &zc); zsadd(zc, - 1l, &zd);

Page 138: Classical CryptoAlgorithms (Ch 01-12)

zdiv(zd, zb, &zl, &zc); zdiv(zy1, zy2, &za, &zc); zexpmod(za, zt, zn, &zc); zexpmod(zv, zl, zn, &za); zmulmod(za, zc, zn, &zu); printf("b = %ld\n", b); printf("n = %ld\n", n); printf("v = %ld\n", v); printf("r_1 = %ld\n", r1); printf("r_2 = %ld\n", r2); printf("y_1 = %ld\n", y1); printf("y_2 = %ld\n", y2); printf("t = "); zwriteln(zt); printf("l = "); zwriteln(zl); printf("u = "); zwriteln(zu); zfree(&za); zfree(&zb); zfree(&zc); zfree(&zd); zfree(&zl); zfree(&zn); zfree(&zt); zfree(&zu); zfree(&zv); zfree(&zr1); zfree(&zr2); zfree(&zy1); zfree(&zy2); return 0;}

Chapter 10 Authentication Codes

10.1 ex1001.c (3,415)

10.4 ex1004.c (1,550)

Exercises

10.1 ex1001.c (3,415)

/* Author: Pate Williams (c) 1997

Exercise 10.1 "Compute Pd_0 and Pd_1 for the following authenication code, represented in matrix

Page 139: Classical CryptoAlgorithms (Ch 01-12)

form:

key 1 2 3 4 1 1 1 2 3 2 1 2 3 1 3 2 1 3 1 4 2 3 1 2 5 3 2 1 3 6 3 3 2 1

The probability distributions on S and K are as follows:

p_s(1) = p_s(4) = 1 / 6, p_s(2) = p_s(3) = 1 / 3 p_k(1) = p_k(6) = 1 / 4, p_k(2) = p_k(3) = 1 / 8 p_k(4) = p_k(5) = 1 / 8.

What are the optimal impersonation and substitution stategies?" -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 325.*/

#include <stdio.h>

int main(void){ double Pd_0 = 0.0, Pd_1 = 0.0, sum; double payoff[5][4], p_k[7], p_s[5]; double p[5][4], po[5][4][5][4]; long A[7][5], a, ap, k, s, sp;

A[1][1] = 1, A[1][2] = 1, A[1][3] = 2, A[1][4] = 3; A[2][1] = 1, A[2][2] = 2, A[2][3] = 3, A[2][4] = 1; A[3][1] = 2, A[3][2] = 1, A[3][3] = 3, A[3][4] = 1; A[4][1] = 2, A[4][2] = 3, A[4][3] = 1, A[4][4] = 2; A[5][1] = 3, A[5][2] = 2, A[5][3] = 1, A[5][4] = 3; A[6][1] = 3, A[6][2] = 3, A[6][3] = 2, A[6][4] = 1; p_s[1] = p_s[4] = 1.0 / 6.0; p_s[2] = p_s[3] = 1.0 / 3.0; p_k[1] = p_k[6] = 1.0 / 4.0; p_k[2] = p_k[3] = p_k[4] = p_k[5] = 1.0 / 8.0; printf("the authenication matrix is:\n"); for (k = 1; k <= 6; k++) { printf("%ld ", k); for (s = 1; s <= 4; s++) printf("%ld ", A[k][s]); printf("\n"); } printf("the source probabilities are:\n"); for (s = 1; s <= 4; s++) printf("%7.5lf ", p_s[s]); printf("\nthe key probabilities are:\n"); for (k = 1; k <= 6; k++) printf("%7.5lf ", p_k[k]); printf("\nthe payoffs are:\n"); for (s = 1; s <= 4; s++) {

Page 140: Classical CryptoAlgorithms (Ch 01-12)

for (a = 1; a <= 3; a++) { sum = 0.0; for (k = 1; k <= 6; k++) if (a == A[k][s]) sum += p_k[k]; payoff[s][a] = sum; if (sum > Pd_0) Pd_0 = sum; printf("%7.5lf ", sum); } printf("\n"); } printf("Pd_0 = %7.5lf\n", Pd_0); printf("the optimal impersonation strategy is:\n"); for (s = 1; s <= 4; s++) { for (a = 1; a <= 3; a++) if (payoff[s][a] == Pd_0) printf("(%ld, %ld) ", s, a); } printf("\n"); for (s = 1; s <= 4; s++) { for (a = 1; a <= 3; a++) { for (sp = 1; sp <= 4; sp++) { for (ap = 1; ap <= 3; ap++) { sum = 0.0; for (k = 1; k <= 6; k++) if (A[k][s] == a && A[k][sp] == ap) sum += p_k[k]; po[s][a][sp][ap] = sum; } } sum = 0.0; for (sp = 1; sp <= 4; sp++) { for (ap = 1; ap <= 3; ap++) if (po[s][a][sp][a] > sum) sum = po[s][a][sp][ap]; } p[s][a] = sum; } } printf("the p_s,a matrix is:\n"); for (s = 1; s <= 4; s++) { for (a = 1; a <= 3; a++) { Pd_1 += p_s[s] * payoff[s][a] * p[s][a]; printf("%7.5lf ", p[s][a]); } printf("\n"); } printf("Pd_1 = %7.5lf\n", Pd_1); printf("the optimal substitution strategy is:\n"); for (s = 1; s <= 4; s++) { for (a = 1; a <= 3; a++) { printf("(%ld, %ld) -> ", s, a); sum = p[s][a]; for (sp = 1; sp <= 4; sp++) for (ap = 1; ap <= 3; ap++) if (sum == po[s][a][sp][ap]) printf("(%ld, %ld) ", sp, ap); printf("\n"); }

Page 141: Classical CryptoAlgorithms (Ch 01-12)

} return 0;}

10.4 ex1004.c (1,550)

/* Author: Pate Williams (c) 1997

Exercise 10.4 "Construct an orthogonal array OA(3, 13, 3)." -Douglas R. Stinson- See "Cryptography: Theory and Practice by Douglas R. Stinson page 325.*/

#include <stdio.h>

long radix_representation(long b, long A, long *a){ long i = 0, q, x = A;

q = x / b, a[i] = x - q * b; while (q > 0) i++, x = q, q = x / b, a[i] = x - q * b; return i + 1;}

int main(void){ int found; long count = 0, i, j, k, length, p = 3, s; long R[27][3], C[27][3];

printf("R\n"); for (i = 0; i < 27; i++) { length = radix_representation(3, i, R[i]); for (j = length; j < 3; j++) R[i][j] = 0; for (j = 2; j >= 0; j--) printf("%d", R[i][j]); printf(" "); if ((i + 1) % 8 == 0) printf("\n"); } for (i = 0; i < 27; i++) { found = 0; for (j = 2; !found && j >= 0; j--) { found = R[i][j] != 0; if (found) k = j; } if (found) { if (R[i][k] == 1) { for (j = 0; j < 3; j++) C[count][j] = R[i][j]; count++; } }

Page 142: Classical CryptoAlgorithms (Ch 01-12)

} printf("\nC\n"); for (i = 0; i < count; i++) { for (j = 2; j >= 0; j--) printf("%d", C[i][j]); printf(" "); if ((i + 1) % 8 == 0) printf("\n"); } printf("\nOA(3, 13, 3)\n"); for (i = 0; i < 27; i++) { for (j = 0; j < count; j++) { s = 0; for (k = 2; k >= 0; k--) s += R[i][k] * C[j][k]; s %= p; printf("%d ", s); } printf("\n"); } return 0;}

Chapter 11 Secret Sharing Schemes

11.1 te1101.c (5,577)

11.1 ex1101.c (6,774)

Example

11.1 te1101.c (5,577)

/* Author: Pate Williams (c) 1997

Example 11.1 "Suppose that p = 17, t = 3, and w = 5; and the public x-co-ordinates are x[i] = i, 1 <= i <= 5. Suppose that B = {P[1], P[3], P[5]}, pool their shares, which are respectively 8, 10, and 11. Determine the key." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 329.*/

#include <stdio.h>#include <stdlib.h>

Page 143: Classical CryptoAlgorithms (Ch 01-12)

#define SIZE 256

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

long Lagrange(long p, long t, long *x, long *y)/* computes the key using the Lagrange interpolation formula, returns the key */{ long bj, i, j, k, s = 0;

for (j = 0; j < t; j++) { bj = 1; for (k = 0; k < t; k++) { if (j != k) { i = (x[k] - x[j]) % p; if (i < 0) i += p; bj = (((bj * x[k]) % p) * Extended_Euclidean(i, p)) % p; } } s = (s + (bj * y[j]) % p) % p; } if (s < 0) s += p; return s;}

long share(long p, long t, long x, long *a){ long j, s;

s = a[t - 1]; for (j = t - 2; j >= 0; j--) s = ((s * x) % p + a[j]) % p; if (s < 0) s += p; return s;}

long **create_square_matrix(long n){

Page 144: Classical CryptoAlgorithms (Ch 01-12)

long i, **matrix = calloc(n, sizeof(long *));

if (!matrix) { fprintf(stderr, "fatal error\ninsufficient memory\n"); fprintf(stderr, "from create_matrix\n"); exit(1); } for (i = 0; i < n; i++) { matrix[i] = calloc(n, sizeof(long)); if (!matrix[i]) { fprintf(stderr, "fatal error\ninsufficient memory\n"); fprintf(stderr, "from create_matrix\n"); exit(1); } } return matrix;}

void delete_square_matrix(long n, long **matrix){ long i;

for (i = 0; i < n; i++) free(matrix[i]); free(matrix);}

void Euclid_extended(long a, long b, long *u, long *v, long *d){ long q, t1, t3, v1, v3;

*u = 1, *d = a; if (b == 0) { *v = 0; return; } v1 = 0, v3 = b; while (v3 != 0) { q = *d / v3; t3 = *d - q * v3; t1 = *u - q * v1; *u = v1, *d = v3; v1 = t1, v3 = t3; } *v = (*d - a * *u) / b;}

long inv(long number, long modulus){ long d, u, v;

Euclid_extended(number, modulus, &u, &v, &d); if (d == 1) return u; return 0;}

void gaussian_elimination(long n, long p,

Page 145: Classical CryptoAlgorithms (Ch 01-12)

long *b, long *x, long **m){ int found; long *d = calloc(n, sizeof(long)), ck, dj; long i, j, k, l, sum, t;

if (!d) { fprintf(stderr, "fatal error\ninsufficient memory\n"); fprintf(stderr, "from gaussian_elimination\n"); exit(1); } for (j = 0; j < n; j++) { found = 0, i = j; while (!found && i < n) { found = m[i][j] != 0; if (!found) i++; } if (!found) { fprintf(stderr, "fatal error\nnon-invertible matrix\n"); fprintf(stderr, "from gaussian_elimination\n"); for (k = 0; k < n; k++) { for (l = 0; l < n; l++) printf("%ld ", m[k][l]); printf("\n"); } exit(1); } if (i > j) { /* swap elements */ for (l = j; l < n; l++) t = m[i][l], m[i][l] = m[j][l], m[j][l] = t; t = b[i], b[i] = b[j], b[j] = t; } dj = d[j] = inv(m[j][j], p); if (dj == 0) { fprintf(stderr, "fatal error\nnon-invertlible element\n"); fprintf(stderr, "from gaussian elimination"); fprintf(stderr, "element %ld mod %ld\n", m[j][j], p); exit(1); } for (k = j + 1; k < n; k++) { ck = (dj * m[k][j]) % p; for (l = j + 1; l < n; l++) { m[k][l] = (m[k][l] - ck * m[j][l]) % p; if (m[k][l] < 0) m[k][l] += p; } b[k] = (b[k] - ck * b[j]) % p; if (b[k] < 0) b[k] += p; } } for (i = n - 1; i >= 0; i--) { sum = 0; for (j = i + 1; j < n; j++) sum += (m[i][j] * x[j]) % p; if (sum < 0) sum += p; x[i] = (d[i] * (b[i] - sum)) % p;

Page 146: Classical CryptoAlgorithms (Ch 01-12)

if (x[i] < 0) x[i] += p; }}

void solve(long p, long t, long *a, long *x, long *y){ long i, j, k, q, z; long **A = create_square_matrix(t);

for (i = 0; i < t; i++) { z = x[i]; for (j = 0; j < t; j++) { q = 1; for (k = 1; k <= j; k++) q = (q * z) % p; A[i][j] = q; } } printf("the matrix is:\n"); for (i = 0; i < t; i++) { for (j = 0; j < t; j++) printf("%5ld ", A[i][j]); printf("\n"); } gaussian_elimination(t, p, y, a, A); delete_square_matrix(t, A);}

int main(void){ long i, p = 17, s, t = 3; long a[3]; long x[3] = {1, 3, 5}; long y[3] = {8, 10, 11}; long z[3] = {8, 10, 11};

printf("====\n"); printf("x y\n"); printf("====\n"); for (i = 0; i < 3; i++) printf("%ld %2ld\n", x[i], y[i]); printf("====\n"); printf("key = %ld\n", Lagrange(p, t, x, y)); solve(p, t, a, x, y); for (i = 0; i < t; i++) printf("a[%ld] = %ld\n", i, a[i]); for (i = 0; i < t; i++) { s = share(p, t, x[i], a); if (s != z[i]) { printf("*error*\nin calculation of share %ld\n", i + 1); printf("%ld %ld\n", s, y[i]); } } return 0;}

Exercise

Page 147: Classical CryptoAlgorithms (Ch 01-12)

11.1 ex1101.c (6,774)

/* Author: Pate Williams (c) 1997

Exercise 11.1 "Write a computer program to compute the key for a Shamir (t, w)-threshold scheme implemented in Z_p. That is, given t public x-coordinates, x_1, x_2,..., x_t, and t y-coordinates y_1, y_2,..., y_t, compute the resulting key. Use the Lagrange interpolation method, as it is easier to program. (a) Test your program if p = 31847, t = 5, and w = 10, with the following shares: x_1 = 413 y_1 = 25439 x_2 = 432 y_2 = 14847 x_3 = 451 y_3 = 24780 x_4 = 470 y_4 = 5910 x_5 = 489 y_5 = 12734 x_6 = 508 y_1 = 12492 x_7 = 527 y_2 = 12555 x_8 = 546 y_3 = 28578 x_9 = 565 y_4 = 20806 x_10 = 584 y_5 = 21462 Verify that the same key is computed using several different subsets of the five shares. (b) Having determined the key, compute the share that would be given to a participant with x-coordinate 10000." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson pages 359-360.*/

#include <stdio.h>#include <stdlib.h>

#define SIZE 256

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n); t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; }

Page 148: Classical CryptoAlgorithms (Ch 01-12)

if (b0 != 1) return 0; else return t % n;}

long Lagrange(long p, long t, long *x, long *y)/* computes the key using the Lagrange interpolation formula, returns the key */{ long bj, i, j, k, s = 0;

for (j = 0; j < t; j++) { bj = 1; for (k = 0; k < t; k++) { if (j != k) { i = (x[k] - x[j]) % p; if (i < 0) i += p; bj = (((bj * x[k]) % p) * Extended_Euclidean(i, p)) % p; } } s = (s + (bj * y[j]) % p) % p; } if (s < 0) s += p; return s;}

long share(long p, long t, long x, long *a){ long j, s;

s = a[t - 1]; for (j = t - 2; j >= 0; j--) s = ((s * x) % p + a[j]) % p; if (s < 0) s += p; return s;}

long **create_square_matrix(long n){ long i, **matrix = calloc(n, sizeof(long *));

if (!matrix) { fprintf(stderr, "fatal error\ninsufficient memory\n"); fprintf(stderr, "from create_matrix\n"); exit(1); } for (i = 0; i < n; i++) { matrix[i] = calloc(n, sizeof(long)); if (!matrix[i]) { fprintf(stderr, "fatal error\ninsufficient memory\n"); fprintf(stderr, "from create_matrix\n"); exit(1); } } return matrix;}

void delete_square_matrix(long n, long **matrix)

Page 149: Classical CryptoAlgorithms (Ch 01-12)

{ long i;

for (i = 0; i < n; i++) free(matrix[i]); free(matrix);}

void Euclid_extended(long a, long b, long *u, long *v, long *d){ long q, t1, t3, v1, v3;

*u = 1, *d = a; if (b == 0) { *v = 0; return; } v1 = 0, v3 = b; while (v3 != 0) { q = *d / v3; t3 = *d - q * v3; t1 = *u - q * v1; *u = v1, *d = v3; v1 = t1, v3 = t3; } *v = (*d - a * *u) / b;}

long inv(long number, long modulus){ long d, u, v;

Euclid_extended(number, modulus, &u, &v, &d); if (d == 1) return u; return 0;}

void gaussian_elimination(long n, long p, long *b, long *x, long **m){ int found; long *d = calloc(n, sizeof(long)), ck, dj; long i, j, k, l, sum, t;

if (!d) { fprintf(stderr, "fatal error\ninsufficient memory\n"); fprintf(stderr, "from gaussian_elimination\n"); exit(1); } for (j = 0; j < n; j++) { found = 0, i = j; while (!found && i < n) { found = m[i][j] != 0; if (!found) i++; } if (!found) {

Page 150: Classical CryptoAlgorithms (Ch 01-12)

fprintf(stderr, "fatal error\nnon-invertible matrix\n"); fprintf(stderr, "from gaussian_elimination\n"); for (k = 0; k < n; k++) { for (l = 0; l < n; l++) printf("%ld ", m[k][l]); printf("\n"); } exit(1); } if (i > j) { /* swap elements */ for (l = j; l < n; l++) t = m[i][l], m[i][l] = m[j][l], m[j][l] = t; t = b[i], b[i] = b[j], b[j] = t; } dj = d[j] = inv(m[j][j], p); if (dj == 0) { fprintf(stderr, "fatal error\nnon-invertlible element\n"); fprintf(stderr, "from gaussian elimination"); fprintf(stderr, "element %ld mod %ld\n", m[j][j], p); exit(1); } for (k = j + 1; k < n; k++) { ck = (dj * m[k][j]) % p; for (l = j + 1; l < n; l++) { m[k][l] = (m[k][l] - ck * m[j][l]) % p; if (m[k][l] < 0) m[k][l] += p; } b[k] = (b[k] - ck * b[j]) % p; if (b[k] < 0) b[k] += p; } } for (i = n - 1; i >= 0; i--) { sum = 0; for (j = i + 1; j < n; j++) sum += (m[i][j] * x[j]) % p; if (sum < 0) sum += p; x[i] = (d[i] * (b[i] - sum)) % p; if (x[i] < 0) x[i] += p; }}

void solve(long p, long t, long *a, long *x, long *y){ long i, j, k, q, z; long **A = create_square_matrix(t);

for (i = 0; i < t; i++) { z = x[i]; for (j = 0; j < t; j++) { q = 1; for (k = 1; k <= j; k++) q = (q * z) % p; A[i][j] = q; } } printf("the matrix is:\n"); for (i = 0; i < t; i++) {

Page 151: Classical CryptoAlgorithms (Ch 01-12)

for (j = 0; j < t; j++) printf("%5ld ", A[i][j]); printf("\n"); } gaussian_elimination(t, p, y, a, A); delete_square_matrix(t, A);}

int main(void){ long i, p = 31847, r = 10000, t = 5; long a[5], u[5], v[5]; long x[10] = {413, 432, 451, 470, 489, 508, 527, 546, 565, 584}; long y[5] = {25439, 14847, 24780, 5910, 12734}; long z[5] = {12492, 12555, 28578, 20806, 21462};

for (i = 0; i < 10; i++) { printf("%ld ", x[i]); if (i < t) printf("%5ld\n", y[i]); else printf("%5ld\n", z[i - t]); } u[0] = x[0], v[0] = y[0]; u[1] = x[1], v[1] = y[1]; u[2] = x[4], v[2] = y[4]; u[3] = x[5], v[3] = z[0]; u[4] = x[6], v[4] = z[1]; printf("key = %ld\n", Lagrange(p, t, x, y)); printf("key = %ld\n", Lagrange(p, t, x + 5, z)); printf("key = %ld\n", Lagrange(p, t, u, v)); for (i = 0; i < t; i++) v[i] = y[i]; solve(p, t, a, x, v); printf("the polynomial coefficients are:\n"); for (i = 0; i < t; i++) printf("a[%ld] = %ld\n", i, a[i]); for (i = 0; i < t; i++) printf("%ld %5ld %5ld\n", x[i], y[i], share(p, t, x[i], a)); x[4] = r, y[4] = share(p, t, r, a); printf("x = %ld y = %ld\n", x[4], y[4]); printf("key = %ld\n", Lagrange(p, t, x, y)); return 0;}

Chapter 12 Pseudo-random Number Generation

12.2 ex1202.c (1,056)

12.3 ex1203.c (1,772)

12.6 ex1206.c (3,383)

Page 152: Classical CryptoAlgorithms (Ch 01-12)

Exercises

12.2 ex1202.c (1,056)

/* Author: Pate Williams (c) 1997

Exercise 12.2 "Suppose we have an RSA Generator with n = 36863, b = 229 and seed s_0 = 25. Compute the first 100 bits produced by this generator." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 385.*/

#include <stdio.h>

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } return a;}

int main(void){ long b = 229, n = 36863l, s_0 = 25; long c_0 = 0, c_1 = 0, i, s, t;

printf("b = %ld\n", b); printf("n = %ld\n", n); printf("s_0 = %ld\n", s_0); printf("the first 100 bits are:\n"); for (i = 0; i < 100; i++) { s = exp_mod(s_0, b, n); s_0 = s; t = s & 1; if (!t) c_0++; else c_1++; printf("%ld", t); if ((i + 1) % 25 == 0) printf("\n"); } printf("count of 0's = %ld\n", c_0); printf("count of 1's = %ld\n", c_1); return 0;}

12.3 ex1203.c (1,772)

Page 153: Classical CryptoAlgorithms (Ch 01-12)

/* Author: Pate Williams (c) 1997

Exercise 12.3 "A PRBG based on the Discrete Logarithm problem is given in Figure 12.11. Suppose p = 21383, the primitive element alpha = 5 and the seed s_0 = 15886. Compute the first 100 bits produced by this generator." -Douglas R. Stinson- See "Cryptography: Theory and Practice" by Douglas R. Stinson page 385.*/

#include <stdio.h>

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } return a;}

int main(void){ long alpha = 5, p = 21383, x_0 = 15886; long c_0 = 0, c_1 = 0, i, p2 = p / 2, x, z;

printf("alpha = %ld\n", alpha); printf("p = %ld\n", p); printf("x_0 = %ld\n", x_0); printf("the first 100 bits are:\n"); for (i = 0; i < 100; i++) { x = exp_mod(alpha, x_0, p); x_0 = x; z = (x > p2) ? 1 : 0; if (!z) c_0++; else c_1++; printf("%ld", z); if ((i + 1) % 25 == 0) printf("\n"); } printf("count of 0's = %ld\n", c_0); printf("count of 1's = %ld\n", c_1); return 0;}

12.6 ex1206.c (3,383)

/* Author: Pate Williams (c) 1997

Exercise 12.6

Page 154: Classical CryptoAlgorithms (Ch 01-12)

"Suppose Bob receives some ciphertext which was encrypted with the Blum-Goldwasser Probabilistic Public-key Cryptosystem. The original plaintext consisted of English text. Each alphabetic character was converted to a bitstring of length five in an obvious way: A -> 00000, B -> 00001, ..., Z -> 11001. The plaintext consisted of 236 alphabetic characters, so a bitstring of length 1180 resulted. This bitstring was then encrypted. The resulting ciphertext was then converted to a hexadecimal representation, to save space. The final string of 295 hexadecimal characters is presented in Table 12.4. Also, s_1181 = 20291 is part of the ciphertext, and n = 29893 is Bob's public key. Bob's secret factorization of n is n = pq, where p = 167 and q = 179. Your task is to decrypt the given ciphertext and restore the original plaintext." -Douglas R. Stinson-*/

#include <stdio.h>

#define BITS_PER_LONG 32#define BITS_PER_LONG_1 31#define SIZE 256

long exp_mod(long x, long b, long n)/* returns x ^ b mod n */{ long a = 1l, s = x;

while (b != 0) { if (b & 1l) a = (a * s) % n; b >>= 1; if (b != 0) s = (s * s) % n; } return a;}

long get_bit(long i, long *sieve){ long b = i % BITS_PER_LONG; long c = i / BITS_PER_LONG;

return (sieve[c] >> (BITS_PER_LONG_1 - b)) & 1;}

long Extended_Euclidean(long b, long n){ long b0 = b, n0 = n, t = 1, t0 = 0, temp, q, r;

q = n0 / b0; r = n0 - q * b0; while (r > 0) { temp = t0 - q * t; if (temp >= 0) temp = temp % n; else temp = n - (- temp % n);

Page 155: Classical CryptoAlgorithms (Ch 01-12)

t0 = t; t = temp; n0 = b0; b0 = r; q = n0 / b0; r = n0 - q * b0; } if (b0 != 1) return 0; else return t % n;}

long Chinese_Remainder(long r, long *a, long *m){ long i, N = 1, M[SIZE], y[SIZE], x = 0;

for (i = 0; i < r; i++) N *= m[i]; for (i = 0; i < r; i++) { M[i] = N / m[i]; y[i] = Extended_Euclidean(M[i], m[i]); x += (a[i] * M[i] * y[i]) % N; } return x;}

int main(void){ long ciphertext[18] = {0xe1866663, 0xf17fdbd1, 0xdc8c8fd2, 0xeebc36ad, 0x7f53795d, 0xba3c9ce2, 0x2dc9a9c7, 0xe2a56455, 0x501399ca, 0x6b98aed2, 0x2c346a52, 0x9a09c193, 0x6c61ecde, 0x10b43d22, 0x6ec683a6, 0x69929f2f, 0xfb912bfa, 0x96a83021}; long p = 167, q = 179, l1 = 1181, s1 = 20291; long a1, a2, b1, b2, s0; long n = p * q, p1 = p - 1, q1 = q - 1; long a[2], m[2], r = 2, bits = 18 * BITS_PER_LONG; long bit[5], i = 0, j, k, z;

a1 = exp_mod((p + 1) / 4, l1, p1); a2 = exp_mod((q + 1) / 4, l1, q1); b1 = exp_mod(s1, a1, p); b2 = exp_mod(s1, a2, q); a[0] = b1; a[1] = b2; m[0] = p; m[1] = q; s0 = Chinese_Remainder(r, a, m); for (j = 0; j < bits / 5; j++) { for (k = 0; k < 5; k++) { s1 = (s0 * s0) % n; s0 = s1; z = s1 & 1; bit[k] = z ^ get_bit(i++, ciphertext); }

Page 156: Classical CryptoAlgorithms (Ch 01-12)

z = bit[0]; for (k = 1; k < 5; k++) z = z * 2 + bit[k]; printf("%c", z + 'A'); if ((j + 1) % 20 == 0) printf("\n"); } return 0;}