From 3fe24df1237a77549ba64c6331383a9a40aed1de Mon Sep 17 00:00:00 2001 From: emkael Date: Sat, 25 Nov 2017 16:15:54 +0100 Subject: Initial BigDeal sources --- .gitignore | 1 + bigdeal.h | 66 ++++ binomial.c | 139 ++++++++ binomial.h | 7 + collect.c | 112 ++++++ collect.h | 3 + dos.c | 162 +++++++++ main.c | 655 +++++++++++++++++++++++++++++++++++ makefile | 46 +++ mingw.c | 171 +++++++++ mp.c | 133 +++++++ mp.h | 12 + os.h | 8 + output.c | 1132 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ output.h | 5 + rmd160.c | 273 +++++++++++++++ rmd160.h | 125 +++++++ test.c | 678 ++++++++++++++++++++++++++++++++++++ types.h | 10 + unix.c | 177 ++++++++++ 20 files changed, 3915 insertions(+) create mode 100644 .gitignore create mode 100644 bigdeal.h create mode 100644 binomial.c create mode 100644 binomial.h create mode 100644 collect.c create mode 100644 collect.h create mode 100644 dos.c create mode 100644 main.c create mode 100644 makefile create mode 100644 mingw.c create mode 100644 mp.c create mode 100644 mp.h create mode 100644 os.h create mode 100644 output.c create mode 100644 output.h create mode 100644 rmd160.c create mode 100644 rmd160.h create mode 100644 test.c create mode 100644 types.h create mode 100644 unix.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5761abc --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.o diff --git a/bigdeal.h b/bigdeal.h new file mode 100644 index 0000000..75450e1 --- /dev/null +++ b/bigdeal.h @@ -0,0 +1,66 @@ +/* + * $Header: /home/sater/bridge/bigdeal/RCS/bigdeal.h,v 1.7 2000/08/27 14:13:20 sater Exp $ + */ + +/* + * Program wide defines for Big Deal + */ + +#define VERSION_MAJOR 1 +#define VERSION_MINOR 2 + +#define COMPASS_NORTH 0 +#define COMPASS_EAST 1 +#define COMPASS_SOUTH 2 +#define COMPASS_WEST 3 +#define NCOMPASS 4 + +#define SUIT_SPADES 0 +#define SUIT_HEARTS 1 +#define SUIT_DIAMONDS 2 +#define SUIT_CLUBS 3 +#define NSUIT 4 + +#define NCARDSPERHAND 13 +#define NCARDSPERDECK 52 + +#define L (96/8) /* Bytes needed for 96 bit arithmetic */ + +/* Baseforms and typedefs for various internal forms of hand */ + +#define BF_GOEDEL 0 +typedef +struct deal_num { + byte dn_num[L]; +} dl_num; + +#define BF_INTERNAL 1 +typedef +struct deal_internal { + byte di_hand[NCOMPASS][NCARDSPERHAND]; +} dl_int; + +#define BF_BYHAND 2 +typedef +struct deal_byhand { + byte dh_hand[NCOMPASS][NCARDSPERHAND]; +} dl_byh; + +#define BF_BYCARD 3 +typedef +struct deal_bycard { + byte dc_card[NCARDSPERDECK]; +} dl_byc; + +#define NBASEFORM 4 + +/* End of baseforms and typedefs */ + +/* + * Various parameters for the program go in here + * to be able to be passed to routines more easily + */ +typedef +struct prog_params { + int pp_nboards; +} progparams_t, *progparams_p; diff --git a/binomial.c b/binomial.c new file mode 100644 index 0000000..7e565c1 --- /dev/null +++ b/binomial.c @@ -0,0 +1,139 @@ +#include "types.h" +#include "bigdeal.h" +#include "mp.h" + +static char rcsid[] = "$Header: /home/sater/bridge/bigdeal/RCS/binomial.c,v 1.11 2000/08/16 15:06:30 sater Exp $"; + +/* + * functions implementing or using the (n over k) mathematical construct + */ + +static byte pascal_triangle[NCARDSPERDECK+1][NCARDSPERHAND+1][L]; + +void +binomial_start() +/* + * Precomputes all numbers (n over k) with k<=NCARDSPERHAND and + * n<=NCARDSPERDECK. + * Numbers are stored in pascal_triangle[][] with L bytes precision (96 bits) + * + * Calculation method is the addition from the top of the triangle + * where the equation: + * n_over_k(n,k) = n_over_k(n-1, k-1) + n_over_k(n-1, k) + * except for some boundary condition situations + */ +{ + int i,j,min; + + for (i=0; i<=NCARDSPERDECK; i++) { + if (idn_num); + + for (compass=COMPASS_NORTH; compass g + */ + if (mp96_cmp(tmp2, g) > 0) + break; + } + n_over_k(13*(NCOMPASS-compass)-a-j, 13-j, tmp1); + n_over_k(13*(NCOMPASS-compass)-b-j, 13-j, tmp2); + mp96_sub(tmp3, tmp1, tmp2); + /* + * tmp1 is assigned the value x_j + */ + mp96_mul(tmp1, tmp3, c); + /* + * g_j = g_{j-1} - x_j + */ + mp96_sub(g, g, tmp1); + dip->di_hand[compass][j] = b; + /* + * a is set to a_j + */ + a = b; + } + } +} diff --git a/binomial.h b/binomial.h new file mode 100644 index 0000000..94517f8 --- /dev/null +++ b/binomial.h @@ -0,0 +1,7 @@ +/* + * $Header: /home/sater/bridge/bigdeal/RCS/binomial.h,v 1.2 1999/12/11 09:41:28 sater Exp $ + */ + +void binomial_start(); +void n_over_k(int n, int k, byte *b); +void code_to_hand(dl_num *dnp, dl_int *dip); diff --git a/collect.c b/collect.c new file mode 100644 index 0000000..e800edd --- /dev/null +++ b/collect.c @@ -0,0 +1,112 @@ +/* + * Collect various pieces of randomness + */ + +static char rcsid[] = "$Header: /home/sater/bridge/bigdeal/RCS/collect.c,v 1.7 2000/08/25 15:55:26 sater Exp $"; + +#include "types.h" +#include "rmd160.h" +#include "bigdeal.h" +#include + +static dword MDbuf[RMDdwords]; /* Contains state of RIPEMD-160 */ +static byte variousbytes[64]; +static int vbytesindex; + +int nrandombits; /* Collected bits of randomness */ +static int nhashbytes; /* Number of bytes hashed */ + +#ifdef BIGDEALX +extern FILE *flog; +#endif + +void +collect_start() +/* + * Set everything to zero, and init the hashing engine + */ +{ + + MDinit(MDbuf); + vbytesindex = 0; + nhashbytes = 0; + nrandombits = 0; +} + +static void +collect_byte(byte b) +/* + * Throw another byte into the machine. If it fills up the buffer run the + * buffer through the hashing engine + */ +{ + dword X[16]; + int i; + byte *bp; + + nhashbytes++; + variousbytes[vbytesindex++] = b; + if (vbytesindex == 64) { + bp = variousbytes; + for (i=0; i<16; i++) { + X[i] = BYTES_TO_DWORD(bp); + bp += 4; + } + compress(MDbuf, X); + vbytesindex = 0; +#ifdef BIGDEALX + if (flog) + fprintf(flog, "compressed another 64 bytes\n"); +#endif + } +} + +void +collect_more(byte *bp, int nbytes, int entropybits) +/* + * Throw a bunch of information into the machine. + * The user supplies a hopefully pessimistic estimate of the entropy + */ +{ + + nrandombits += entropybits; +#ifdef BIGDEALX + if (flog) { + int i; + + fprintf(flog, "collect_more("); + for (i=0; i < nbytes; i++) + fprintf(flog, "%02x", bp[i]); + fprintf(flog, ", %d, %d) -> %d\n", nbytes, entropybits, nrandombits); + } +#endif + while(nbytes > 0) { + collect_byte(*bp); + nbytes--; + bp++; + } +} + +void +collect_finish(byte *hash) +/* + * Halt the hashing engine + * Extract the result into hash[] + */ +{ + int i; + + MDfinish(MDbuf, variousbytes, nhashbytes, 0); +#ifdef BIGDEALX + if (flog) + fprintf(flog, "collected %d random bits, from %d bytes of data\n", + nrandombits, nhashbytes); + +#endif + for (i=0; i>2]; /* implicit cast to byte */ + hash[i+1] = (MDbuf[i>>2] >> 8); /* extracts the 8 least */ + hash[i+2] = (MDbuf[i>>2] >> 16); /* significant bits. */ + hash[i+3] = (MDbuf[i>>2] >> 24); + } +} diff --git a/collect.h b/collect.h new file mode 100644 index 0000000..40aaeac --- /dev/null +++ b/collect.h @@ -0,0 +1,3 @@ +void collect_more(byte*, int, int); +void collect_start(); +void collect_finish(byte *); diff --git a/dos.c b/dos.c new file mode 100644 index 0000000..271c972 --- /dev/null +++ b/dos.c @@ -0,0 +1,162 @@ + +static char rcsid[] = "$Header: /home/sater/bridge/bigdeal/RCS/dos.c,v 1.9 2000/08/26 14:15:22 sater Exp $"; + +#include +#include +#include +#include +#include "types.h" +#include "bigdeal.h" +#include "collect.h" + +extern FILE *flog; + +/* + * Find the best clock to use in this environment + * We prefer uclock, since it generates more bits + * But it is not ansi, so use clock as an alternative + */ +#ifdef UCLOCKS_PER_SEC +int +bestclock() +{ + + return (int) uclock(); +} +#else +#ifdef CLOCKS_PER_SEC +int +bestclock() +{ + + return (int) clock(); +} +#else +There is no clock, this program needs it, so do not compile +#endif +#endif + +#define MAX_INTERVAL_ENTROPY 6 + +int +getchtm(int *nbits) +/* + * Read one character from standard input + * Time the wait, and use bits for random + * MUST be in cbreak mode for this to work + */ +{ + int t1, t2; + int tdiff; + int c; + int shift; + int b; + + /* + * First get the best clock we have + */ + t1 = bestclock(); + /* + * Now get one character + */ + c = getch(); + /* + * If it is zero, which can happen with getch() under DOS + * we have a two character sequence(function key probably) + * and we make one character out of it by appending the next + */ + if (c == 0) + c = getch() + 256; + /* + * and get the clock after the keypress + */ + t2 = bestclock(); + /* + * Number of ticks we waited goes to tdiff + */ + tdiff = t2 - t1; + /* + * Now we are going to believe half the bits we get + */ + for (shift = tdiff, b = 0; shift>2 ; shift >>= 2, b++) + ; + if (b < MAX_INTERVAL_ENTROPY) + *nbits = b; + else + *nbits = MAX_INTERVAL_ENTROPY; + /* + * We send all the bits to the collect pool + * but do not count the bits yet (parameter 0) + * because higher layers might decide not to believe this + * character, and its associated timing + */ + collect_more((byte *) &t1, sizeof(t1), 0); + collect_more((byte *) &t2, sizeof(t2), 0); + if (flog) + fprintf(flog, "Collected character %d, timediff %d, timebits %d\n", + c, tdiff, *nbits); + return c; +} + +void +os_collect() { + time_t t; + + (void) time(&t); + /* Trust 6 bits of seconds */ + collect_more((byte *) &t, sizeof(t), 6); +} + +void +cbreak() +{ + +} + +void +cooked() +{ + +} + +void +os_start() +{ + + /* + * Start the clock running + */ + (void) bestclock(); + +} + +void +os_finish() +{ + +} + +int +legal_filename_prefix(char *s) +/* + * Legal prefix to make legal name when three letter suffix added + */ +{ + + if (*s == 0) /* Too short */ + return 0; + if (strlen(s) > 8) + return 0; + while (*s) { + if (!isalnum(*s) && *s != '-' && *s != '_') + return 0; + s++; + } + return 1; +} + +char *os_init_file_name() +{ + + return "bigdeal.ini"; +} diff --git a/main.c b/main.c new file mode 100644 index 0000000..bd3e299 --- /dev/null +++ b/main.c @@ -0,0 +1,655 @@ +#include +#include +#include + +#include "types.h" +#include "rmd160.h" +#include "bigdeal.h" +#include "mp.h" +#include "binomial.h" +#include "output.h" +#include "os.h" +#include "collect.h" + +static char rcsid[] = "$Header: /home/sater/bridge/bigdeal/RCS/main.c,v 1.26 2000/09/08 05:13:44 sater Exp $"; + +#define MESSLEN 100 /* Length of input buffer(s) */ +#define ENTROPY_TO_COLLECT RMDsize*4/3 /* 33% extra safety/paranoia */ + +progparams_t parameters; /* Program parameters go in here */ +FILE *flog; /* Not used in safe version */ + +static int +readline(FILE *ifile, char *buf, int len) +/* + * Read line into buf + * Check for length, discard trailing \n + */ +{ + char *eol; + + if(fgets(buf, len, ifile) == NULL) + return 0; + eol = strchr(buf, '\n'); + if (eol) + *eol = 0; + return 1; +} + +/* + * Section that handles initialization file + * Currently in use for hand format(s) + * + * File contains keyword=value lines + * The init_file[] array contains default values, overwritten by file + */ + +static char init_header[] = "[BigDeal]"; + +char default_formats[MESSLEN] = "dup,pbn"; +char default_askformats[MESSLEN] = "no"; +char default_owner[MESSLEN] = "Identification of owner or tournament"; + +#define LONGESTKEYWORD 20 /* Extra bytes to read for keyword and = */ +struct ifrecord { + char *if_keyword; + char *if_value; +} init_file[] = { + { "formats", default_formats }, + { "askformats", default_askformats }, + { "owner", default_owner }, + { 0 } +}; + +void +write_init_file(char *ifname) +/* + * Prompt for defaults, and write init_file + */ +{ + FILE *ifile; + char buf1[MESSLEN], buf2[MESSLEN]; + struct ifrecord *ifrp; + + printf("This program can generate various hand formats, one or more per run:\n\n"); + output_help(); + do { + printf("Give comma separated list of formats usually desired: [%s] ", + default_formats); + readline(stdin, buf1, MESSLEN); + if (buf1[0] == 0) + strcpy(buf1, default_formats); + strcpy(buf2, buf1); + } while (output_specify_formats(buf2, 0)==0); + strcpy(default_formats, buf1); + + printf("\nNormally you will always use the format(s) just specified,\n"); + printf("but maybe you would like to change it for some runs.\n"); + printf("Do you want the program to reconfirm the format every run? [%s] ", default_askformats); + readline(stdin, buf1, MESSLEN); + if (buf1[0]) + strcpy(default_askformats, buf1[0] == 'y' ? "yes" : "no"); + + printf("\nIf you give an identification string the program will ensure\n"); + printf("that nobody with a different identification can generate the\n"); + printf("same sets of deals as you\n"); + printf("identication? [%s]\n? ", default_owner); + readline(stdin, buf1, MESSLEN); + if (buf1[0]) + strcpy(default_owner, buf1); + + ifile = fopen(ifname, "w"); + fprintf(ifile, "%s\n", init_header); + for (ifrp=init_file; ifrp->if_keyword; ifrp++) { + fprintf(ifile, "%s=%s\n", ifrp->if_keyword, ifrp->if_value); + } + fclose(ifile); +} + +void +read_init_file(char *ifname, int write_when_absent) +/* + * Read init file + */ +{ + FILE *ifile; + char buf[MESSLEN+LONGESTKEYWORD]; + char *eqptr; + struct ifrecord *ifrp; + + ifile = fopen(ifname, "r"); + if (ifile == NULL) { + if (write_when_absent) + write_init_file(ifname); + return; + } + while (readline(ifile, buf, MESSLEN+LONGESTKEYWORD)) { + if (buf[0] == 0) + continue; /* empty line */ + if (strcmp(buf, init_header)==0) + continue; /* header for Windows routines */ + if (buf[0] == '[') + break; /* end of our stuff */ + eqptr = strchr(buf, '='); + if (eqptr == 0) { + fprintf(stderr, "Line '%s' does not contain =\n", buf); + fprintf(stderr, "Suggest rerun program with -R flag\n"); + continue; + } + *eqptr++ = 0; + for (ifrp=init_file; ifrp->if_keyword; ifrp++) { + if (strcmp(ifrp->if_keyword, buf)==0) { + strcpy(ifrp->if_value, eqptr); + break; + } + } + if (!ifrp->if_keyword) { + fprintf(stderr, "Keyword %s in init_file unknown\n", buf); + fprintf(stderr, "Suggest rerun program with -R flag\n"); + } + } + fclose(ifile); +} + +#ifndef BIGDEALX +/* + * All parameters for the program when it is running in binary or safe mode + * In this mode the program should be as idiot proof as possible + */ +#define OPTION_STRING "f:n:p:R" +#define USAGE_STRING "[-n number-of-deals] [-p outputfile-prefix] [-f output-format-list] [-R(re-init)]" +#define MAXDEALS 100 /* No more than 100 deals in standard prog */ +#define VERSION_COMMENT "" + +#else /* BIGDEALX */ +/* + * Parameters for the other mode. This is the hacker mode where the user + * can tinkle with entropy and other operations that increase the likelyhood + * of the program generating something else than a random, never occurred + * before set of deals. + */ +#define OPTION_STRING "e:E:f:h:n:op:R" +#define USAGE_STRING "[-n nr-of-deals] [-p ofile-prefx] [-f o-format-list] [-e entropy-str] [-E entropy-file] [-o(only entropy from command line)] [-h hash] [-R(re-init)]" +#define MAXDEALS 1000000000 +#define VERSION_COMMENT "(Extended version, not recommended for tournament use)" + +#define HISTNAME "dealentr.txt" +#define LOGNAME "deallog.txt" + +/* + **************************************************************************** + * Begin section of code for other mode only + **************************************************************************** + */ + +static void +checkduphash(char *hash) +/* + * Paranoia function: if in test we ever run into the same 160 bit number again + * it is time to reevaluate our assumptions + */ +{ + FILE *fhist; + char oldhash[MESSLEN]; + int hashlen; + int counter, badentry; + + hashlen = strlen(hash); + fhist = fopen(HISTNAME, "a+"); + if (fhist == NULL) { + fprintf(stderr, "Couldn't open %s\n", HISTNAME); + return; + } + counter = 0; + badentry = 0; + fseek(fhist, 0L, 0); + while (readline(fhist, oldhash, MESSLEN)) { + if (strlen(oldhash) != hashlen) { + badentry++; + continue; + } + if (strcmp(oldhash, hash) == 0) { + fprintf(flog, "Panic: same hash, index %d\n", counter); + fprintf(stderr, "Panic: same hash, index %d\n", counter); + exit(-1); + } + counter++; + } + fprintf(fhist, "%s\n", hash); + fclose(fhist); + fprintf(flog, "Checked hash against %d previous hashes\n", counter); + if (badentry) { + fprintf(flog, "The file %s contained %d bad entries\n", + HISTNAME, badentry); + } +} + +static void +read_entropy_from_file(char *fname) +/* + * A frontend has generated entropy for us. + * Let us hope it did the right thing. + * We give it credit for 4 bits entropy per byte. + */ +{ + FILE *fentr; + int c; + + if (fname == 0) { + fprintf(stderr, "No entropy file supplied\n"); + return; + } + fentr = fopen(fname, "r"); + if (fentr == NULL) { + fprintf(stderr, "Cannot open %s\n", fname); + return; + } + while ((c = getc(fentr)) >= 0) { + collect_more((byte *) &c, sizeof(c), 4); + } + fclose(fentr); +} + +static int +hexval(char c) +/* + * Convert characters '0'..'9', 'A'..'F' and 'a'..'f' to 0..15 + */ +{ + + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + fprintf(stderr, "Character %c is not a hexchar\n", c); + exit(-1); +} + +static void +random_set(char *hashstr, byte *sr) +/* + * hashstr is a 40 byte string of hex characters + * we convert it into a 20 byte(160 bit) binary value + */ +{ + int i; + + if (strlen(hashstr) != 2*RMDbytes) { + fprintf(stderr, "Argument %s should be %d characters long\n", + hashstr, 2*RMDbytes); + exit(-1); + } + for (i=0; i=64; nbytes-=64) { + for (i=0; i<16; i++) { + X[i] = BYTES_TO_DWORD(value); + value += 4; + } + compress(MDbuf, X); + } + + /* finish: */ + MDfinish(MDbuf, value, length, 0); + + for (i=0; i>2]; /* implicit cast to byte */ + hashcode[i+1] = (MDbuf[i>>2] >> 8); /* extracts the 8 least */ + hashcode[i+2] = (MDbuf[i>>2] >> 16); /* significant bits. */ + hashcode[i+3] = (MDbuf[i>>2] >> 24); + } + + return (byte *)hashcode; +} + +static int +goedel(dl_num *dnp) +/* + * Checks whether the contents of dnp is a number less than the number + * of bridge deals. + */ +{ + /* + * This number is precomputed + */ + static byte nr_bridge_deals[L] = + { 173,85,227,21,99,77,218,101,139,244,146,0}; + +#ifdef BIGDEALX + byte a[L], b[L]; + + n_over_k(52,13,a); + n_over_k(39,13,b); + mp96_mul(a,a,b); + n_over_k(26,13,b); + mp96_mul(a,a,b); + + /* + * This gives a the value of the number of bridge deals + * =( (52 over 13) times (39 over 13) times (26 over 13) ) + * Now let us check our internal calculations + * + * If it is wrong we miscalculated somewhere + */ + + if (mp96_cmp(a, nr_bridge_deals) != 0) { + fprintf(stderr, "Miscalculation\n"); + /* + * print_goedel(stderr, (dl_num*) a); + * print_goedel(stderr, (dl_num*) nr_bridge_deals); + */ + exit(-1); + } +#endif + + if (mp96_cmp(dnp->dn_num, nr_bridge_deals) >= 0) + return 0; /* too big, not a hand number */ + return 1; +} + +extern int nrandombits; + +static void +get_entropy_from_keyboard() { + int c, oldc; + int nbits; + + cbreak(); + printf("Type random characters until you are told to stop "); + oldc = 0; + do { + c = getchtm(&nbits); + if (c != oldc) { + /* + * Collect the character, assume 2 bits entropy + * plus what the timing supplied. + */ + collect_more( (byte*)&c, sizeof(c), 2+nbits); + oldc = c; + } + } while (nrandombits < ENTROPY_TO_COLLECT); + printf("\nThat is enough\007\n"); + cooked(); +} + +/* + * Structure with all values that get hashed for random generation + * This includes hash of owner identication making it impossible for + * another owner to generate the same series of deals + * Reduces 2**-160 chance to zero + */ +static struct { + byte seed_sequence[4]; /* sequence number in PRNG sequence */ + byte seed_random[RMDbytes]; /* 160 bits collected at start */ + byte seed_owner[RMDbytes]; /* 160 bit hash of owner ident */ +} seed; + +int +main (int argc, char *argv[]) +{ + int i; + char message[MESSLEN]; + byte *hashcode; + unsigned long seqno; + dl_num dnumber; + char filename[MESSLEN] = ""; + int c; + extern char *optarg; + char *formats = 0; +#ifdef BIGDEALX + int only_arg_entropy = 0; + char *hashstr = 0; + int dangerous_code_used = 0; +#else +#define only_arg_entropy 0 +#endif + + /* + * Say hi to operator + */ + printf("Big Deal version %d.%d%s\n\n", + VERSION_MAJOR, VERSION_MINOR, VERSION_COMMENT); + +#ifdef BIGDEALX + flog = fopen(LOGNAME, "a"); +#endif + os_start(); + collect_start(); + + while ((c = getopt(argc, argv, OPTION_STRING)) != -1) { + switch(c) { +#ifdef BIGDEALX + case 'E': + read_entropy_from_file(optarg); + dangerous_code_used = 1; + break; + case 'e': + collect_more((byte *) optarg, strlen(optarg), 4*strlen(optarg)); + dangerous_code_used = 1; + break; + case 'h': + hashstr = optarg; + /* fall through */ + case 'o': + only_arg_entropy = 1; + dangerous_code_used = 1; + break; +#endif + case 'p': + strncpy(filename, optarg, MESSLEN-1); + break; + case 'f': + formats = optarg; + break; + case 'n': + parameters.pp_nboards = atoi(optarg); + break; + case 'R': + read_init_file(os_init_file_name(), 0); + write_init_file(os_init_file_name()); + exit(0); + case '?': + fprintf(stderr, "Usage: %s %s\n", argv[0], USAGE_STRING); + exit(-1); + } + } + + if (!only_arg_entropy) + os_collect(); + + read_init_file(os_init_file_name(), 1); + binomial_start(); + /* + * Read number of boards to generate + */ + while(parameters.pp_nboards <= 0 || parameters.pp_nboards > MAXDEALS) { + /* + * If we are asked to generate more than 100 boards refuse + * We only have 160 bits entropy, and no one plays sessions + * of more than 100 boards anyhow + */ + if (parameters.pp_nboards > MAXDEALS) { + parameters.pp_nboards = 0; + printf("The maximum is %d, run program again for more\n", + MAXDEALS); + } + printf("Number of boards to deal(1-%d): ", MAXDEALS); + (void) readline(stdin, message, MESSLEN); + parameters.pp_nboards = atoi(message); + /* + * Collect the string, no entropy assumed + */ + if (!only_arg_entropy) + collect_more( (byte*)message, strlen(message), 0); + } + + /* + * Read part of filename before the . + */ + while(!legal_filename_prefix(filename)) { + printf("Output filename(without suffix): "); + (void) readline(stdin, message, MESSLEN); + /* + * Collect the string, 5 bits entropy assumed + */ + if (!only_arg_entropy) + collect_more( (byte*)message, strlen(message), 5); + strcpy(filename,message); + } + + /* + * Get output formats + */ + if (formats == 0) { + /* + * Not specified on command line + */ + if (strcmp(default_askformats, "yes")==0) { + printf("Hand format(s) to generate: [%s] ", + default_formats); + (void) readline(stdin, message, MESSLEN); + if (message[0]) { + strcpy(default_formats, message); + } + } + formats = default_formats; + } + + /* + * If we do not have enough entropy collected (very likely) + * let the user supply it by rattling his keyboard + */ + if (!only_arg_entropy && nrandombits < ENTROPY_TO_COLLECT) { + get_entropy_from_keyboard(); + } + + + /* + * Extract the entropy into the random part of the seed + */ + collect_finish(seed.seed_random); +#ifdef BIGDEALX + if (nrandombits < ENTROPY_TO_COLLECT) { + /* + * Can only happen when only_arg_entropy is set + */ + printf("WARNING: entropy supplied is dangerously low!!!\n"); + } + if (dangerous_code_used) { + printf("You used features in this extended version of Big Deal\n"); + printf("that might defeat the purpose(generating unique sequences).\n"); + printf("Use hands for actual play only with permission from your national authority.\n\n"); + } + + /* + * Did someone use the -h flag ? + */ + if (hashstr) + random_set(hashstr, seed.seed_random); + + /* + * Start checking for duplicate hashes, and log current hash + */ + for (i=0; i>8) & 0xFF; + seed.seed_sequence[2] = (seqno>>16) & 0xFF; + seed.seed_sequence[3] = (seqno>>24) & 0xFF; + /* + * Run all the bits through the hash + */ + hashcode = RMDhash((byte *) &seed, sizeof(seed)); + /* + * Take the first L bytes(96 bits) as a candidate + * hand number + */ + memcpy(dnumber.dn_num, hashcode, L); + } while(!goedel(&dnumber)); + /* + * Ok, got one + * Print it in all desired formats + */ + output_hand(i, &dnumber); + } + + /* + * Finished, close output files + */ + output_closefiles(); +#ifdef BIGDEALX + fclose(flog); +#endif + + /* + * Do whatever our OS wants us to do at the end, and then exit + */ + os_finish(); + return 0; +} diff --git a/makefile b/makefile new file mode 100644 index 0000000..2428155 --- /dev/null +++ b/makefile @@ -0,0 +1,46 @@ +# +# Makefile for the shuffle program Big Deal +# +# $Header: /home/sater/bridge/bigdeal/RCS/Makefile,v 1.4 2000/08/16 15:18:56 sater Exp $ +# +# Change OS to either unix or dos +OS=unix + +CC=gcc +PFLAGS= +CFLAGS=-O $(PFLAGS) -Wall -pedantic -I/mingw/include +LDFLAGS=$(PFLAGS) + +COMMONOBJS=rmd160.o mp.o binomial.o +SAFEOBJS=main.o collect.o output.o +EXTNOBJS=mainx.o collectx.o outputx.o + + +all: bigdeal bigdealx + +bigdeal: $(COMMONOBJS) $(SAFEOBJS) $(OS).o + $(CC) $(LDFLAGS) -o bigdeal $(COMMONOBJS) $(SAFEOBJS) $(OS).o + +bigdealx: $(COMMONOBJS) $(EXTNOBJS) $(OS).o + $(CC) $(LDFLAGS) -o bigdealx $(COMMONOBJS) $(EXTNOBJS) $(OS).o + +clean: + -rm main.o rmd160.o mp.o binomial.o output.o collect.o dos.o unix.o + +mainx.o: main.c + $(CC) $(CFLAGS) -c -DBIGDEALX main.c -o mainx.o + +collectx.o: collect.c + $(CC) $(CFLAGS) -c -DBIGDEALX collect.c -o collectx.o + +outputx.o: output.c mp.h + $(CC) $(CFLAGS) -c -DBIGDEALX output.c -o outputx.o + +main.o: main.c types.h rmd160.h bigdeal.h mp.h binomial.h output.h os.h collect.h +output.o: output.c types.h bigdeal.h binomial.h +binomial.o: binomial.c types.h bigdeal.h mp.h +collect.o: collect.c types.h rmd160.h bigdeal.h +dos.o: dos.c types.h bigdeal.h +mp.o: mp.c types.h bigdeal.h +rmd160.o: rmd160.c types.h rmd160.h +unix.o: unix.c types.h bigdeal.h diff --git a/mingw.c b/mingw.c new file mode 100644 index 0000000..dbea580 --- /dev/null +++ b/mingw.c @@ -0,0 +1,171 @@ + +static char rcsid[] = "$Header: /home/sater/bridge/bigdeal/RCS/dos.c,v 1.9 2000/08/26 14:15:22 sater Exp $"; + +#include +#include +#include +#include +#include +#include "types.h" +#include "bigdeal.h" +#include "collect.h" + +extern FILE *flog; + +static int highfreqclock; +static LARGE_INTEGER frequency, epoch; + +void +os_start() +{ + + /* + * Start the clock running + */ + if (QueryPerformanceFrequency(&frequency) == 0) { + highfreqclock = 0; + } else { + highfreqclock = 1; + QueryPerformanceCounter(&epoch); + if (flog) + fprintf(flog, "Clock frequency %I64d, epoch %I64d\n", + frequency.QuadPart, epoch.QuadPart); + } +} + +void +os_finish() +{ + +} + +int bestclock() +{ + LARGE_INTEGER t; + + if (highfreqclock) { + QueryPerformanceCounter(&t); + /* compute the elapsed time in ticks */ + return (t.QuadPart - epoch.QuadPart); + } +#ifdef UCLOCKS_PER_SEC + return (int) uclock(); +#else +#ifdef CLOCKS_PER_SEC + return (int) clock(); +#else +There is no clock, this program needs it, so do not compile +#endif +#endif +} + +#define MAX_INTERVAL_ENTROPY 6 + +int +getchtm(int *nbits) +/* + * Read one character from standard input + * Time the wait, and use bits for random + * MUST be in cbreak mode for this to work + */ +{ + int t1, t2; + int tdiff; + int c; + int shift; + int b; + + /* + * First get the best clock we have + */ + t1 = bestclock(); + /* + * Now get one character + */ + c = getch(); + /* + * If it is zero, which can happen with getch() under DOS + * we have a two character sequence(function key probably) + * and we make one character out of it by appending the next + */ + if (c == 0) + c = getch() + 256; + /* + * and get the clock after the keypress + */ + t2 = bestclock(); + /* + * Number of ticks we waited goes to tdiff + */ + tdiff = t2 - t1; + /* + * Now we are going to believe half the bits we get + */ + for (shift = tdiff, b = 0; shift>2 ; shift >>= 2, b++) + ; + if (b < MAX_INTERVAL_ENTROPY) + *nbits = b; + else + *nbits = MAX_INTERVAL_ENTROPY; + /* + * We send all the bits to the collect pool + * but do not count the bits yet (parameter 0) + * because higher layers might decide not to believe this + * character, and its associated timing + */ + collect_more((byte *) &t1, sizeof(t1), 0); + collect_more((byte *) &t2, sizeof(t2), 0); + + if (flog) + fprintf(flog, "Collected character %d, timediff %d, timebits %d\n", + c, tdiff, b); + return c; +} + +void +os_collect() { + int pid; + FILETIME systime; + + collect_more((byte *) &frequency, sizeof(frequency), 0); + collect_more((byte *) &epoch, sizeof(epoch), 8); + pid = getpid(); + collect_more((byte *) &pid, sizeof(pid), 3); +} + +void +cbreak() +{ + +} + +void +cooked() +{ + +} + +int +legal_filename_prefix(char *s) +/* + * Legal prefix to make legal name when three letter suffix added + */ +{ + + if (*s == 0) /* Too short */ + return 0; + if (strlen(s) > 50) + return 0; + while (*s) { + if (!isalnum(*s) && *s != '-' && *s != '_') + return 0; + s++; + } + return 1; +} + +char *os_init_file_name() +{ + + return "bigdeal.ini"; +} diff --git a/mp.c b/mp.c new file mode 100644 index 0000000..ed9a51c --- /dev/null +++ b/mp.c @@ -0,0 +1,133 @@ +#include "types.h" +#include "bigdeal.h" +#include + +static char rcsid[] = "$Header: /home/sater/bridge/bigdeal/RCS/mp.c,v 1.10 2000/08/16 15:06:05 sater Exp $"; + +/* + * Multiple precision arithmetic + * Format is 12 byte number( 96 bits), with lowest byte most significant + * (socalled bigendian format) + */ + +void +mp96_zero(byte *b) +/* + * Sets b to zero + */ +{ + + memset(b, 0, L); +} + +void +mp96_one(byte *b) +/* + * Sets b to one + */ +{ + + memset(b, 0, L-1); + b[L-1] = 1; +} + +void +mp96_assign(byte *b, byte *b1) +/* + * Assign b1 to b + */ +{ + + memcpy(b, b1, L); +} + +int +mp96_add(byte *b,byte *b1,byte *b2) +/* + * Computes b=b1+b2 + * returns carry bit signifying overflow + */ +{ + int i; + unsigned int h,carry; + + carry = 0; + for (i=L-1; i>=0; i--) { + h = b1[i]+b2[i]+carry; + carry = h>=256 ? 1 : 0; + b[i] = h; /* Truncates to 8 bits automatically */ + } + return carry; +} + +int +mp96_sub(byte *b,byte *b1,byte *b2) +/* + * Computes b=b1-b2 + * returns borrow bit signifying overflow + */ +{ + int i,h; + unsigned int borrow; + + borrow = 0; + for (i=L-1; i>=0; i--) { + h = b1[i]-b2[i]-borrow; + borrow = h<0 ? 1 : 0; + b[i] = h; + } + return borrow; +} + +int +mp96_cmp(byte *b1, byte *b2) +/* + * Compares b1 with b2 + * returns >0 when b1>b2, <0 when b1=0; i--) { + for (j=L-1; j>i; j--) + bpart[j] = 0; + carry=0; + for (j=i; j>=0; j--) { + h = b1copy[i]*b2copy[L-1+j-i]+carry; + carry = h/256; + bpart[j] = h; + } + (void) mp96_add(b,b,bpart); + } +} diff --git a/mp.h b/mp.h new file mode 100644 index 0000000..c8bcce2 --- /dev/null +++ b/mp.h @@ -0,0 +1,12 @@ +/* + * $Header: /home/sater/bridge/bigdeal/RCS/mp.h,v 1.5 2000/02/28 14:00:21 sater Exp $ + */ + +void mp96_zero(byte *b); +void mp96_one(byte *b); +void mp96_assign(byte *b, byte *b1); + +int mp96_add(byte *b,byte *b1,byte *b2); +int mp96_sub(byte *b,byte *b1,byte *b2); +int mp96_cmp(byte *b1, byte *b2); +void mp96_mul(byte *b,byte *b1,byte *b2); diff --git a/os.h b/os.h new file mode 100644 index 0000000..88708cd --- /dev/null +++ b/os.h @@ -0,0 +1,8 @@ +int getchtm (int *); +void os_start (); +void cooked (); +void os_finish (); +void cbreak (); +void os_collect(); +int legal_filename_prefix(char *s); +char *os_init_file_name(); diff --git a/output.c b/output.c new file mode 100644 index 0000000..b29bcbd --- /dev/null +++ b/output.c @@ -0,0 +1,1132 @@ +#include "types.h" +#include "bigdeal.h" +#include "binomial.h" +#include +#include + +static char rcsid[] = "$Header: /home/sater/bridge/bigdeal/RCS/output.c,v 1.20 2000/09/08 06:01:46 sater Exp $"; + +/* + * Next type is a tagged union to prevent compilers complaining + * Should check on tag + */ +typedef +struct hand_rep { + int hr_baseform; /* Which baseform is this in */ + union { + dl_num *hv_dnp; + dl_int *hv_dip; + dl_byh *hv_dbhp; + dl_byc *hv_dbcp; + } hr_value; +} hr_t, *hr_p; + +static progparams_p prparp; /* All parameters */ + +/* + * Information per output type is collected here + */ +typedef +struct output_format { + char * of_name; /* Name of format */ + int of_flags; /* Various flags */ + FILE * of_file; /* Output file to write it to */ + char * of_suffix; /* File suffix/type */ + int of_baseform; /* Which internal format it is printed from */ + char * of_help; /* Help description */ + void (*of_init)(FILE *f); /* Routine to init */ + void (*of_printit)(FILE *f, int boardno, hr_p arg); /* Routine to print it */ + void (*of_finish)(FILE *f); /* Routine to finish */ +} of_t, *of_p; + +/* + * Values for the of_flags struct member + */ +#define OFF_USEIT 0x1 /* Use the format this run */ +#define OFF_BINARY 0x2 /* Output is binary, not text */ + +static void +cnv_int_byh(dl_int *dip, dl_byh *dbhp) +/* + * Converts the internal handrepresentation from *dip to a "bri" like coding + * in *dbhp. This representation is as follows: + * The 52 cards are numbered 1: AS, 2 KS, .... , 52 2C + * and all thirteen slots for all four hands are filled in with one of + * the 52 cards. + * + * Given the way this program works the order of cards per hand will + * be strictly increasing. + */ +{ + int nextcard[NCARDSPERDECK+1]; + int i; + int card,prevcard; + int skip, skipcnt; + int compass; + + /* + * Setup a chain of 52 cards with a linked list type structure + */ + for (i=0; idi_hand[compass][0]; + else + skip=dip->di_hand[compass][i] - + dip->di_hand[compass][i-1]; + for (skipcnt=0; skipcntdh_hand[compass][i] = card; + /* + * Take card just selected out of the linked list + */ + card = nextcard[card]; + nextcard[prevcard] = card; + } + } +} + +static void +cnv_byh_byc(dl_byh *dbhp, dl_byc *dbcp) +/* + * Convert from a "bri" like coding to a cardposition type coding. + * Representation is an array of 52 cards, from AS to 2C, + * with as a value the compass position, 0 for N, 3 for W + * + * Note the -1 to convert from 1..52 cardnotation to 0..51 array index + */ +{ + int compass, card; + + for (compass = COMPASS_NORTH; compass <= COMPASS_WEST; compass++) + for (card = 0; card < NCARDSPERHAND; card++) + dbcp->dc_card[dbhp->dh_hand[compass][card] - 1] = + compass; +} + +static void +out_fill(FILE *out, char filler, int count) +/* + * Write filler character, count times + */ +{ + int i; + + for(i=0; idh_hand[compass][i]); +} + +/*ARGSUSED*/ +static void +print_bri(FILE *out, int boardno, hr_p hrp) +/* + * Writes out "bri" format, including filler + * + * It is unknown whether the strange half space, half zero fill + * is actually necessary. This is just the way I saw my first BRI file + */ +{ + dl_byh *dbhp = hrp->hr_value.hv_dbhp; + + out_bri(out, dbhp); + out_fill(out, ' ', 32); + out_fill(out, 0, 18); +} + +static void +out_cardrep(FILE *out, dl_byh *dbhp, char *suitstr[NCOMPASS][NSUIT], char *cardrep) +/* + * Write out a "dge" or "pbn" record, no filler + */ +{ + int compass; + int suit; + int i; + int card, card_in_suit; + + for (compass=COMPASS_NORTH; compass<=COMPASS_WEST; compass++) { + for (suit=SUIT_SPADES; suit<=SUIT_CLUBS; suit++) { + fputs(suitstr[compass][suit], out); + for (i=0; idh_hand[compass][i]; + card_in_suit = card - 13*suit; + if (card_in_suit > 0 && card_in_suit <= 13) + putc(cardrep[card_in_suit-1], out); + } + } + } +} + +/* + * International card representation + * + * Maybe this will need to be changed for local formats + */ +static char cardrep_int[13] = "AKQJT98765432"; + +/* + * The suit symbols in the DOS character set + */ +#define DOSCHAR_SPADE 6 +#define DOSCHAR_HEART 3 +#define DOSCHAR_DIAMOND 4 +#define DOSCHAR_CLUB 5 + +static char dosstr_spade[] = { DOSCHAR_SPADE, 0 }; +static char dosstr_heart[] = { DOSCHAR_HEART, 0 }; +static char dosstr_diamond[] = { DOSCHAR_DIAMOND, 0 }; +static char dosstr_club[] = { DOSCHAR_CLUB, 0 }; +static char *dge_suitstr[NCOMPASS][NSUIT] = { + { dosstr_spade, dosstr_heart, dosstr_diamond, dosstr_club }, + { dosstr_spade, dosstr_heart, dosstr_diamond, dosstr_club }, + { dosstr_spade, dosstr_heart, dosstr_diamond, dosstr_club }, + { dosstr_spade, dosstr_heart, dosstr_diamond, dosstr_club }, +}; + +static void +out_dge(FILE *out, dl_byh *dbhp) +/* + * Write out the "dge" record, no filler + */ +{ + + out_cardrep(out, dbhp, dge_suitstr, cardrep_int); +} + +/*ARGSUSED*/ +static void +print_dge(FILE *out, int boardno, hr_p hrp) +/* + * Writes out "dge" format, including filler + */ +{ + dl_byh *dbhp = hrp->hr_value.hv_dbhp; + + out_dge(out, dbhp); + out_fill(out, 0, 60); +} + +/* + * Portable Bridge Notation + * + * We generate PBN "Import" format, according to the instructions + * from KGB + */ +static char pbn_colon[] = ":"; +static char pbn_space[] = " "; +static char pbn_dot[] = "."; +static char *pbn_suitstr[NCOMPASS][NSUIT] = { + { pbn_colon, pbn_dot, pbn_dot, pbn_dot }, + { pbn_space, pbn_dot, pbn_dot, pbn_dot }, + { pbn_space, pbn_dot, pbn_dot, pbn_dot }, + { pbn_space, pbn_dot, pbn_dot, pbn_dot }, +}; + +static void +out_pbn(FILE *out, dl_byh *dbhp) +/* + * Write out the "pbn" record, just the hand itself + */ +{ + + out_cardrep(out, dbhp, pbn_suitstr, cardrep_int); +} + +static char dealerchar[4] = "WNES"; +static char *pbn_vulnrep[] = { "None", "NS", "EW", "All" }; +static int vuln_index[16] = { + 2, 0, 1, 2, + 3, 1, 2, 3, + 0, 2, 3, 0, + 1, 3, 0, 1 +}; + +static void +init_pbn(FILE *out) +{ + + fprintf(out, "%% PBN 1.0\n"); + fprintf(out, "[Generator \"Big Deal version %d.%d\"]\n", + VERSION_MAJOR, VERSION_MINOR); +} + +static void +print_pbn(FILE *out, int boardno, hr_p hrp) +/* + * Write out the "pbn" record, with furnishings + */ +{ + dl_byh *dbhp = hrp->hr_value.hv_dbhp; + + fprintf(out, "[Board \"%d\"]\n", boardno); + fprintf(out, "[Dealer \"%c\"]\n", dealerchar[boardno%4]); + fprintf(out, "[Vulnerable \"%s\"]\n", + pbn_vulnrep[vuln_index[boardno%16]]); + fprintf(out, "[Deal \"N"); + out_pbn(out, dbhp); + fprintf(out, "\"]\n"); + fprintf(out, "\n"); +} + +/* + * CSV format, for database import + */ + +static char csv_begin[] = "\""; +static char csv_intra[] = "\",\""; +static char *csv_suitstr[NCOMPASS][NSUIT] = { + { csv_begin, csv_intra, csv_intra, csv_intra }, + { csv_intra, csv_intra, csv_intra, csv_intra }, + { csv_intra, csv_intra, csv_intra, csv_intra }, + { csv_intra, csv_intra, csv_intra, csv_intra }, +}; +static char *csv_vulnrep[] = { "-", "NS", "EW", "All" }; + +static void +print_csv(FILE *out, int boardno, hr_p hrp) +/* + * Write out a CSV record + */ +{ + dl_byh *dbhp = hrp->hr_value.hv_dbhp; + + out_cardrep(out, dbhp, csv_suitstr, cardrep_int); + fprintf(out, "\",\"%d\",\"%c/%s\"\n", + boardno, + dealerchar[boardno%4], + csv_vulnrep[vuln_index[boardno%16]]); +} + +/* + * DUP and DLM formats, for Jannersten Duplimate machine + */ + +static void +print_dup_common(FILE *out, int boardno, dl_byh *dbhp, int not_on_screen) +/* + * Write out a "dup" record + * This is actually a BRI, followed by a DGE, and some padding + */ +{ + + /* + * Horribly convoluted hack upon hack format + * + * Duplimate, generation X + */ + out_bri(out, dbhp); + if (boardno == 1 && not_on_screen) { + out_fill(out, ' ', 68); + } else { + out_dge(out, dbhp); + } + if (boardno == 1) { + putc('Y', out); /* Y to Random Hands */ + putc('N', out); /* N to reverse order */ + putc('1', out); /* Start at board 1 */ + putc(' ', out); + putc(' ', out); + putc('0', out); /* No copies immediate */ + putc(' ', out); + putc('0' + (prparp->pp_nboards/10)%10, out);/* tens of number */ + putc('0' + prparp->pp_nboards%10, out); /* units of number */ + putc(' ', out); + } else { + out_fill(out, 0, 10); + } +} + +/*ARGSUSED*/ +static void +print_dup(FILE *out, int boardno, hr_p hrp) +{ + dl_byh *dbhp = hrp->hr_value.hv_dbhp; + + print_dup_common(out, boardno, dbhp, 0); +} + +/*ARGSUSED*/ +static void +print_dupblind(FILE *out, int boardno, hr_p hrp) +{ + dl_byh *dbhp = hrp->hr_value.hv_dbhp; + + print_dup_common(out, boardno, dbhp, 1); +} + +static void +init_dlmcommon(FILE *out, int show) +{ + int checksum; + + /* + * Very badly documented, sorry(not my fault) + */ + fprintf(out, "[Document]\n"); + fprintf(out, "Headline=Generated by Big Deal version %d.%d\n", + VERSION_MAJOR, VERSION_MINOR); + fprintf(out, "Status=%s\n", show ? "Show" : "Sealed"); + fprintf(out, "Duplicates=1\n"); + fprintf(out, "From board=1\n"); + fprintf(out, "To board=%d\n", + prparp->pp_nboards<=99 ? prparp->pp_nboards : 99); + fprintf(out, "Next board to duplimate=0\n"); + fprintf(out, "PrintOuts=0\n"); + fprintf(out, "Crypto key=0\n"); + checksum = prparp->pp_nboards; + if (show) + checksum ^= 1; /* XOR with 1 if show */ + fprintf(out, "Checksum=%d\n", checksum); +} + +static void +init_dlm(FILE *out) +{ + + init_dlmcommon(out, 1); +} + +static void +init_dlmblind(FILE *out) +{ + + init_dlmcommon(out, 0); +} + +static void +print_dlm(FILE *out, int boardno, hr_p hrp) +/* + * Writes out one DLM record, including "checksum" + * Record is mainly one lower case character per two cards + */ +{ + dl_byc *dbcp = hrp->hr_value.hv_dbcp; + int i; + int c; + int checksum; + + if (boardno>99) /* Format cannot do more than 99 */ + return; + fprintf(out, "Duplicates %02d=0\n", boardno); + fprintf(out, "Board %02d=", boardno); + checksum = boardno; + for(i=0; idc_card[2*i+0]<<2; + c += dbcp->dc_card[2*i+1]<<0; + putc(c, out); + checksum ^= c; + } + fprintf(out, "%03d\n", checksum); +} + +static void +finish_dlm(FILE *out) +/* + * For some reason a DLM file always contains exactly 99 hands + * fill it up with bogus hands here + */ +{ + int i; + int checksum; + + for (i=prparp->pp_nboards+1; i<=99; i++) { + checksum = i^14; /* KGB calculated */ + fprintf(out, "Duplicates %02d=0\n", i); + fprintf(out, "Board %02d=aaaaaabffffffkkkkkklpppppp%03d\n", + i, checksum); + } +} + +/*ARGSUSED*/ +static void +print_ber(FILE *out, int boardno, hr_p hrp) +/* + * Writes out "ber" format, no filler or separators + */ +{ + dl_byc *dbcp = hrp->hr_value.hv_dbcp; + int i; + + for(i=0; idc_card[i], out); +} + +/* + * Borel files contain lines of 52 characters [A-Za-z] + * A is AS to z is 2c + * For some reason the line does not start with the cards of North + * but the cards of the dealer. + */ +static void +init_borel(FILE *out) +{ + + fprintf(out, "\n"); +} + +static void +print_borel(FILE *out, int boardno, hr_p hrp) +/* + * Write out a "bhg" record + */ +{ + dl_byh *dbhp = hrp->hr_value.hv_dbhp; + int i, j, compass, card; + + for (i=0; idh_hand[compass][j]; + putc(card <= 2*NCARDSPERHAND ? + 'A'+card-1 : 'a'+card-2*NCARDSPERHAND-1, + out); + } + } + fprintf(out, "\n"); +} + +#ifdef BIGDEALX + +#include "mp.h" + +/* + * A decimal number corresponding to a deal has maximum 29 digits + */ +#define MAXDECIMALS 29 +static byte powers_of_ten[MAXDECIMALS][L]; + +static void +init_goedel(FILE *out) +{ + int i; + byte ten[L]; + + /* + * Initialize the array with powers of ten + * We need them in the next function + */ + mp96_zero(ten); + ten[L-1] = 10; + mp96_one(powers_of_ten[0]); + for (i=1; ihr_value.hv_dnp; + byte value[L]; + int i; + int decimal; + int zero_suppress; + char outchar; + + mp96_assign(value, dnp->dn_num); + zero_suppress = 1; + for (i=MAXDECIMALS-1; i>=0; i--) { + /* + * Since we do not have division we do repeated subtraction + */ + decimal = 0; + while (mp96_cmp(value, powers_of_ten[i])>=0) { + mp96_sub(value, value, powers_of_ten[i]); + decimal++; + } + if (decimal) { + outchar = decimal + '0'; + zero_suppress = 0; + } else { + /* + * Suppress leading zeroes + * Special case all zeroes also handled + * That will be the day.... + */ + outchar = zero_suppress && i ? ' ' : '0'; + } + putc(outchar, out); + /* + * Intersperse with commas for readability + */ + if (i%3 == 0) { + putc(i==0 ? '\n' : zero_suppress ? ' ' : ',', out); + } + } +} + +/* + * Statistics computation: + * There is a strong argument *not* to print statistics of a set of deals + * since it leads itself to abuse only too easily. + * Therefore this is only included in the non-safe version. + */ + +static struct { + int st_sumsquare; + int st_hcp[NCOMPASS]; + int st_hcpfreq[38]; /* 0..37, maximum points per hand */ + int st_lsuitfreq[NCOMPASS][14]; /* 4..13, longest suit per compass */ + int st_longestsuit; /* longest suit in whole set */ +} stats; + +/* + * Theoretical values taken from Encyclopedia, fourth edition, page 278 + */ +static int theory_hcpfreq[38] = { /* times 10000 */ + 3639, /* 0 */ + 7884, /* 1 */ + 13561, /* 2 */ + 24624, /* 3 */ + 38454, /* 4 */ + 51862, /* 5 */ + 65541, /* 6 */ + 80281, /* 7 */ + 88922, /* 8 */ + 93562, /* 9 */ + 94051, /* 10 */ + 89447, /* 11 */ + 80269, /* 12 */ + 69143, /* 13 */ + 56933, /* 14 */ + 44237, /* 15 */ + 33109, /* 16 */ + 23617, /* 17 */ + 16051, /* 18 */ + 10362, /* 19 */ + 6435, /* 20 */ + 3779, /* 21 */ + 2100, /* 22 */ + 1119, /* 23 */ + 559, /* 24 */ + 264, /* 25 */ + 117, /* 26 */ + 49, /* 27 */ + 19, /* 28 */ + 7, /* 29 */ + 2, /* 30 */ + 1, 1, 1, 1, 1, 1, 1 /* 31..37 */ +}; + +static int theory_lsuitfreq[14] = { /* probability * 1000000 */ + 0, 0, 0, 0, /* cannot be 0 1 2 3 */ + 350805, /* 4 */ + 443596, /* 5 */ + 165477, /* 6 */ + 35265, /* 7 */ + 4668, /* 8 */ + 370, /* 9 */ + 16, /* 10 */ + 0, 0, 0 /* 11 .. 13 */ +}; + + +static int high_card_points[13] = { 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +/*ARGSUSED*/ +static void +init_stat(FILE *out) +{ + + /* + * Warn of consequences of looking at statistics + */ + printf("\nStatistics will be produced in an accompanying file.\n"); + printf("Usage of these statistics for a decision on whether or when\n"); + printf("to play this set of deals is a violation of the spirit of the\n"); + printf("Laws of Duplicate Contract Bridge.\n\n"); + printf("STATISTICS ARE FOR DISPLAY PURPOSES ONLY!!\n\n"); + /* + * At this point initialize counters if non-zero + */ +} + +/*ARGSUSED*/ +static void +compute_stat(FILE *out, int boardno, hr_p hrp) +/* + * Compute statistics on this hand + */ +{ + dl_byh *dbhp = hrp->hr_value.hv_dbhp; + int i, compass, card; + int length, maxlength, suitlength[NCOMPASS][NSUIT]; + int hcp; + + for (compass=0; compassdh_hand[compass][i]-1; + /* + * card/13 should be suit + */ + suitlength[compass][card/13]++; + /* + * card%13 should be pip + */ + hcp += high_card_points[card%13]; + } + stats.st_hcp[compass] += hcp; + stats.st_hcpfreq[hcp]++; + maxlength = 0; + for (i=0; i maxlength) + maxlength = length; + stats.st_sumsquare += length*length; + } + if (maxlength > stats.st_longestsuit) + stats.st_longestsuit = maxlength; + stats.st_lsuitfreq[compass][maxlength]++; + } + /* + * Now suitlength[][] contains all suit lengths for all hands + * 16 numbers in all. + * Statistics about distribution to be added here. + */ +} + +static void +print_avg(FILE *out, int sum, int divisor, int decimals, char *termstr) +/* + * Prevent use of floating point + */ +{ + int power_of_ten; + int i; + int result; + + power_of_ten = 1; + for (i=0; ipp_nboards); + + fprintf(out, "Average sum of squares: "); + print_avg(out, stats.st_sumsquare, prparp->pp_nboards, 0, "\n"); + + fprintf(out, "Average points NESW: "); + print_avg(out, stats.st_hcp[0], prparp->pp_nboards, 2, " "); + print_avg(out, stats.st_hcp[1], prparp->pp_nboards, 2, " "); + print_avg(out, stats.st_hcp[2], prparp->pp_nboards, 2, " "); + print_avg(out, stats.st_hcp[3], prparp->pp_nboards, 2, "\n"); + + fprintf(out, "Frequency of high card points per hand:\n"); + for (i=0; i<38; i++) { + if (stats.st_hcpfreq[i] == 0) + continue; + fprintf(out, "%2d points: ", i); + print_avg(out, stats.st_hcpfreq[i]*100, prparp->pp_nboards*4, 4, "% ("); + print_avg(out, theory_hcpfreq[i], 10000, 4, "%)\n"); + } + + fprintf(out, "Frequency of longest suitlength per compass:\n"); + fprintf(out, "%8s%8s%8s%8s%8s Theory\n", "Length", + "North", "East", "South", "West"); + for(length = 4; length <= stats.st_longestsuit; length++) { + fprintf(out, "%8d%8d%8d%8d%8d ", length, + stats.st_lsuitfreq[COMPASS_NORTH][length], + stats.st_lsuitfreq[COMPASS_EAST][length], + stats.st_lsuitfreq[COMPASS_SOUTH][length], + stats.st_lsuitfreq[COMPASS_WEST][length]); + print_avg(out, 100*theory_lsuitfreq[length], + 100000000/prparp->pp_nboards, 1, "\n"); + } +} +#endif + +/* + * All formats are set to not in use. + * The output_specify_formats routine will set the wanted formats + */ +static +of_t output_formats[] = { + { "dup", OFF_BINARY, NULL, ".dup", BF_BYHAND, + "Duplimate format", + 0, print_dup, 0 }, + { "dupblind", OFF_BINARY, NULL, ".dup", BF_BYHAND, + "Duplimate format, no cards on screen", + 0, print_dupblind, 0 }, + { "dlm", 0, NULL, ".dlm", BF_BYCARD, + "New Duplimate format", + init_dlm, print_dlm, finish_dlm }, + { "dlmblind", 0, NULL, ".dlm", BF_BYCARD, + "New Duplimate format, no cards on screen", + init_dlmblind, print_dlm, finish_dlm }, + { "bri", OFF_BINARY, NULL, ".bri", BF_BYHAND, + "BRI format", + 0, print_bri, 0 }, + { "dge", OFF_BINARY, NULL, ".dge", BF_BYHAND, + "DGE format", + 0, print_dge, 0 }, + { "pbn", 0, NULL, ".pbn", BF_BYHAND, + "Portable Bridge Notation", + init_pbn, print_pbn, 0 }, + { "csv", 0, NULL, ".csv", BF_BYHAND, + "Comma Separated Values", + 0, print_csv, 0 }, + { "ber", OFF_BINARY, NULL, ".ber", BF_BYCARD, + "Bernasconi format", + 0, print_ber, 0 }, + { "borel", 0, NULL, ".bhg", BF_BYHAND, + "Borel Hand Generator format", + init_borel, print_borel, 0 }, +#ifdef BIGDEALX + { "goedel", 0, NULL, ".goe", BF_GOEDEL, + "Internal goedel number format(development only)", + init_goedel, print_goedel, 0 }, + { "stats", 0, NULL, ".txt", BF_BYHAND, + "Statistics on set", + init_stat, compute_stat, print_stat }, + { "stdout", 0, NULL, 0, BF_BYHAND, + "Portable Bridge Notation on standard output", + init_pbn, print_pbn, 0 }, +#endif + { 0 } +}; + +void +output_help() { + of_p ofp; + + printf("%-8s%8s Explanation\n\n", "Name", "Suffix"); + /* For all formats: */ + for (ofp=output_formats; ofp->of_name; ofp++) { + printf("%-8s%8s %s\n", + ofp->of_name, + ofp->of_suffix? ofp->of_suffix : "", + ofp->of_help); + } + printf("\n"); +} + +#define NTOKENS 10 +static char ** +tokenize(char *tokenstring, char separator) +{ + static char *tokenvec[NTOKENS+1]; + char *tsp, *sepp; + int tokencount; + + tsp = tokenstring; + tokencount = 0; + do { + tokenvec[tokencount++] = tsp; + if ((sepp = strchr(tsp, separator)) != 0) { + *sepp++ = 0; + tsp = sepp; + } + } while (sepp && tokencount < NTOKENS); + if (sepp) + fprintf(stderr, "too many words, \"%s\" ignored\n", sepp); + tokenvec[tokencount] = 0; + return tokenvec; +} + +static int +suf_in_use(char *name, char *suffix) +{ + of_p ofp; + + /* + * Check for potential duplicate suffix use + */ + for (ofp=output_formats; ofp->of_name; ofp++) { + if (!(ofp->of_flags&OFF_USEIT)) { + /* + * Format not in use, no problem + */ + continue; + } + if (ofp->of_suffix != 0) { + if (suffix == 0 || strcmp(ofp->of_suffix, suffix) != 0) { + /* + * Not same suffix, no problem + */ + continue; + } + } else { + /* + * To check suffix is 0 (stdout) + */ + if (suffix != 0) { + /* + * One 0, other not, no problem + */ + continue; + } + } + /* + * Ok, we have a problem + */ + fprintf(stderr, "Cannot use %s, because %s shares suffix %s\n", + name, ofp->of_name, suffix ? suffix : "NONE"); + return 1; + } + return 0; +} + +int +output_specify_formats(char *format_string, int for_real) +/* + * Comma separated list of output formats to use + * + * Return value is used to check validity of string + */ +{ + char **ofvector; + of_p ofp; + int found; + int retval; + + retval = 1; /* While all OK */ + for(ofvector = tokenize(format_string, ','); *ofvector; ofvector++) { + found = 0; + for (ofp=output_formats; ofp->of_name; ofp++) { + if (strcmp(ofp->of_name, *ofvector) == 0) { + if (suf_in_use(ofp->of_name, ofp->of_suffix)) { + retval = 0; + } else { + ofp->of_flags |= OFF_USEIT; + } + found++; + break; + } + } + if (!found) { + fprintf(stderr, "Format %s unknown\n", *ofvector); + retval = 0; + } + } + + if (!for_real) { + /* + * This was just a test, clean up + */ + for (ofp=output_formats; ofp->of_name; ofp++) { + ofp->of_flags &= ~OFF_USEIT; + } + } + + return retval; +} + +/* + * This next section is to support multiple internal formats, + * where there is a limited number of possible transformations + * and we try to minimize the internal formats generated + * Just generate what we need + */ +#define bit(x) (1<<(x)) +static int formatset; /* Bitmap of internal formats to support */ +static int formatclosure[NBASEFORM] = { + bit(BF_GOEDEL), + bit(BF_GOEDEL) | bit(BF_INTERNAL), + bit(BF_GOEDEL) | bit(BF_INTERNAL) | bit(BF_BYHAND), + bit(BF_GOEDEL) | bit(BF_INTERNAL) | bit(BF_BYHAND) | bit(BF_BYCARD), +}; + +void +output_createfiles(char *fileprefix, progparams_p ppp) +/* + * Create a file for every wanted output format + * Set the formatset variable + */ +{ + char filename[100]; + of_p ofp; + FILE *f; + + prparp = ppp; + /* For all formats: */ + for (ofp=output_formats; ofp->of_name; ofp++) { + /* If not in use forget it */ + if (!(ofp->of_flags&OFF_USEIT)) + continue; + + /* Make note of internal formats we have to make */ + formatset |= formatclosure[ofp->of_baseform]; + + /* If no suffix use Standard Output */ + if (ofp->of_suffix) { + if (strlen(fileprefix)+strlen(ofp->of_suffix)+1 > + sizeof(filename)) { + fprintf(stderr, "File name %s%s too long(cannot happen)\n", fileprefix, ofp->of_suffix); + exit(-1); + } + strcpy(filename, fileprefix); + strcat(filename, ofp->of_suffix); + f = fopen(filename, ofp->of_flags&OFF_BINARY ? "wb" : "w"); + if (f == NULL) { + fprintf(stderr, "Cannot create %s\n", filename); + exit(-1); + } + ofp->of_file = f; + } else { + ofp->of_file = stdout; + } + /* + * If there is an init routine call it now + */ + if (ofp->of_init) + (*ofp->of_init)(ofp->of_file); + } +} + +void +output_closefiles() +/* + * Close all output files + */ +{ + of_p ofp; + + /* For all formats: */ + for (ofp=output_formats; ofp->of_name; ofp++) { + /* If not in use forget it */ + if (ofp->of_file != NULL) { + /* + * If there is a finish routine call it first + */ + if (ofp->of_finish) + (*ofp->of_finish)(ofp->of_file); + if (ofp->of_suffix) /* So not STDOUT */ + fclose(ofp->of_file); + } + } +} + +void +output_hand(int boardno, dl_num *dnp) +/* + * Convert goedel number to various internal forms as necessary + * Output all desired formats + */ +{ + dl_int dinternal; + dl_byh dbyhand; + dl_byc dbycard; + of_p ofp; + hr_t handrep; + + /* + * First create all necessary internal forms + * Bits in formatset have been inited in output_createfiles + */ + if (formatset&bit(BF_INTERNAL)) + code_to_hand(dnp, &dinternal); + if (formatset&bit(BF_BYHAND)) + cnv_int_byh(&dinternal, &dbyhand); + if (formatset&bit(BF_BYCARD)) + cnv_byh_byc(&dbyhand, &dbycard); + + /* + * Now call output routines + */ + for(ofp = output_formats; ofp->of_name; ofp++) { + if (ofp->of_file == NULL) + continue; + handrep.hr_baseform = ofp->of_baseform; + switch (ofp->of_baseform) { + case BF_GOEDEL: + handrep.hr_value.hv_dnp = dnp; + break; + case BF_INTERNAL: + handrep.hr_value.hv_dip = &dinternal; + break; + case BF_BYHAND: + handrep.hr_value.hv_dbhp = &dbyhand; + break; + case BF_BYCARD: + handrep.hr_value.hv_dbcp = &dbycard; + break; + } + (*ofp->of_printit)(ofp->of_file, boardno, &handrep); + } +} diff --git a/output.h b/output.h new file mode 100644 index 0000000..b32663c --- /dev/null +++ b/output.h @@ -0,0 +1,5 @@ +int output_specify_formats(char *format_string, int for_real); +void output_createfiles(char *fileprefix, progparams_p ppp); +void output_hand(int boardno, dl_num *dnp); +void output_closefiles(); +void output_help(); diff --git a/rmd160.c b/rmd160.c new file mode 100644 index 0000000..75b36fe --- /dev/null +++ b/rmd160.c @@ -0,0 +1,273 @@ +/********************************************************************\ + * + * FILE: rmd160.c + * + * CONTENTS: A sample C-implementation of the RIPEMD-160 + * hash-function. + * TARGET: any computer with an ANSI C compiler + * + * AUTHOR: Antoon Bosselaers, ESAT-COSIC + * DATE: 1 March 1996 + * VERSION: 1.0 + * + * Copyright (c) Katholieke Universiteit Leuven + * 1996, All Rights Reserved + * +\********************************************************************/ + +static char rcsid[] = "$Header: /home/sater/bridge/bigdeal/RCS/rmd160.c,v 1.2 1999/11/28 13:12:21 sater Exp $"; + +/* header files */ +#include +#include +#include +#include "types.h" +#include "rmd160.h" + +/********************************************************************/ + +void MDinit(dword *MDbuf) +{ + MDbuf[0] = 0x67452301UL; + MDbuf[1] = 0xefcdab89UL; + MDbuf[2] = 0x98badcfeUL; + MDbuf[3] = 0x10325476UL; + MDbuf[4] = 0xc3d2e1f0UL; + + return; +} + +/********************************************************************/ + +void compress(dword *MDbuf, dword *X) +{ + dword aa = MDbuf[0], bb = MDbuf[1], cc = MDbuf[2], + dd = MDbuf[3], ee = MDbuf[4]; + dword aaa = MDbuf[0], bbb = MDbuf[1], ccc = MDbuf[2], + ddd = MDbuf[3], eee = MDbuf[4]; + + /* round 1 */ + FF(aa, bb, cc, dd, ee, X[ 0], 11); + FF(ee, aa, bb, cc, dd, X[ 1], 14); + FF(dd, ee, aa, bb, cc, X[ 2], 15); + FF(cc, dd, ee, aa, bb, X[ 3], 12); + FF(bb, cc, dd, ee, aa, X[ 4], 5); + FF(aa, bb, cc, dd, ee, X[ 5], 8); + FF(ee, aa, bb, cc, dd, X[ 6], 7); + FF(dd, ee, aa, bb, cc, X[ 7], 9); + FF(cc, dd, ee, aa, bb, X[ 8], 11); + FF(bb, cc, dd, ee, aa, X[ 9], 13); + FF(aa, bb, cc, dd, ee, X[10], 14); + FF(ee, aa, bb, cc, dd, X[11], 15); + FF(dd, ee, aa, bb, cc, X[12], 6); + FF(cc, dd, ee, aa, bb, X[13], 7); + FF(bb, cc, dd, ee, aa, X[14], 9); + FF(aa, bb, cc, dd, ee, X[15], 8); + + /* round 2 */ + GG(ee, aa, bb, cc, dd, X[ 7], 7); + GG(dd, ee, aa, bb, cc, X[ 4], 6); + GG(cc, dd, ee, aa, bb, X[13], 8); + GG(bb, cc, dd, ee, aa, X[ 1], 13); + GG(aa, bb, cc, dd, ee, X[10], 11); + GG(ee, aa, bb, cc, dd, X[ 6], 9); + GG(dd, ee, aa, bb, cc, X[15], 7); + GG(cc, dd, ee, aa, bb, X[ 3], 15); + GG(bb, cc, dd, ee, aa, X[12], 7); + GG(aa, bb, cc, dd, ee, X[ 0], 12); + GG(ee, aa, bb, cc, dd, X[ 9], 15); + GG(dd, ee, aa, bb, cc, X[ 5], 9); + GG(cc, dd, ee, aa, bb, X[ 2], 11); + GG(bb, cc, dd, ee, aa, X[14], 7); + GG(aa, bb, cc, dd, ee, X[11], 13); + GG(ee, aa, bb, cc, dd, X[ 8], 12); + + /* round 3 */ + HH(dd, ee, aa, bb, cc, X[ 3], 11); + HH(cc, dd, ee, aa, bb, X[10], 13); + HH(bb, cc, dd, ee, aa, X[14], 6); + HH(aa, bb, cc, dd, ee, X[ 4], 7); + HH(ee, aa, bb, cc, dd, X[ 9], 14); + HH(dd, ee, aa, bb, cc, X[15], 9); + HH(cc, dd, ee, aa, bb, X[ 8], 13); + HH(bb, cc, dd, ee, aa, X[ 1], 15); + HH(aa, bb, cc, dd, ee, X[ 2], 14); + HH(ee, aa, bb, cc, dd, X[ 7], 8); + HH(dd, ee, aa, bb, cc, X[ 0], 13); + HH(cc, dd, ee, aa, bb, X[ 6], 6); + HH(bb, cc, dd, ee, aa, X[13], 5); + HH(aa, bb, cc, dd, ee, X[11], 12); + HH(ee, aa, bb, cc, dd, X[ 5], 7); + HH(dd, ee, aa, bb, cc, X[12], 5); + + /* round 4 */ + II(cc, dd, ee, aa, bb, X[ 1], 11); + II(bb, cc, dd, ee, aa, X[ 9], 12); + II(aa, bb, cc, dd, ee, X[11], 14); + II(ee, aa, bb, cc, dd, X[10], 15); + II(dd, ee, aa, bb, cc, X[ 0], 14); + II(cc, dd, ee, aa, bb, X[ 8], 15); + II(bb, cc, dd, ee, aa, X[12], 9); + II(aa, bb, cc, dd, ee, X[ 4], 8); + II(ee, aa, bb, cc, dd, X[13], 9); + II(dd, ee, aa, bb, cc, X[ 3], 14); + II(cc, dd, ee, aa, bb, X[ 7], 5); + II(bb, cc, dd, ee, aa, X[15], 6); + II(aa, bb, cc, dd, ee, X[14], 8); + II(ee, aa, bb, cc, dd, X[ 5], 6); + II(dd, ee, aa, bb, cc, X[ 6], 5); + II(cc, dd, ee, aa, bb, X[ 2], 12); + + /* round 5 */ + JJ(bb, cc, dd, ee, aa, X[ 4], 9); + JJ(aa, bb, cc, dd, ee, X[ 0], 15); + JJ(ee, aa, bb, cc, dd, X[ 5], 5); + JJ(dd, ee, aa, bb, cc, X[ 9], 11); + JJ(cc, dd, ee, aa, bb, X[ 7], 6); + JJ(bb, cc, dd, ee, aa, X[12], 8); + JJ(aa, bb, cc, dd, ee, X[ 2], 13); + JJ(ee, aa, bb, cc, dd, X[10], 12); + JJ(dd, ee, aa, bb, cc, X[14], 5); + JJ(cc, dd, ee, aa, bb, X[ 1], 12); + JJ(bb, cc, dd, ee, aa, X[ 3], 13); + JJ(aa, bb, cc, dd, ee, X[ 8], 14); + JJ(ee, aa, bb, cc, dd, X[11], 11); + JJ(dd, ee, aa, bb, cc, X[ 6], 8); + JJ(cc, dd, ee, aa, bb, X[15], 5); + JJ(bb, cc, dd, ee, aa, X[13], 6); + + /* parallel round 1 */ + JJJ(aaa, bbb, ccc, ddd, eee, X[ 5], 8); + JJJ(eee, aaa, bbb, ccc, ddd, X[14], 9); + JJJ(ddd, eee, aaa, bbb, ccc, X[ 7], 9); + JJJ(ccc, ddd, eee, aaa, bbb, X[ 0], 11); + JJJ(bbb, ccc, ddd, eee, aaa, X[ 9], 13); + JJJ(aaa, bbb, ccc, ddd, eee, X[ 2], 15); + JJJ(eee, aaa, bbb, ccc, ddd, X[11], 15); + JJJ(ddd, eee, aaa, bbb, ccc, X[ 4], 5); + JJJ(ccc, ddd, eee, aaa, bbb, X[13], 7); + JJJ(bbb, ccc, ddd, eee, aaa, X[ 6], 7); + JJJ(aaa, bbb, ccc, ddd, eee, X[15], 8); + JJJ(eee, aaa, bbb, ccc, ddd, X[ 8], 11); + JJJ(ddd, eee, aaa, bbb, ccc, X[ 1], 14); + JJJ(ccc, ddd, eee, aaa, bbb, X[10], 14); + JJJ(bbb, ccc, ddd, eee, aaa, X[ 3], 12); + JJJ(aaa, bbb, ccc, ddd, eee, X[12], 6); + + /* parallel round 2 */ + III(eee, aaa, bbb, ccc, ddd, X[ 6], 9); + III(ddd, eee, aaa, bbb, ccc, X[11], 13); + III(ccc, ddd, eee, aaa, bbb, X[ 3], 15); + III(bbb, ccc, ddd, eee, aaa, X[ 7], 7); + III(aaa, bbb, ccc, ddd, eee, X[ 0], 12); + III(eee, aaa, bbb, ccc, ddd, X[13], 8); + III(ddd, eee, aaa, bbb, ccc, X[ 5], 9); + III(ccc, ddd, eee, aaa, bbb, X[10], 11); + III(bbb, ccc, ddd, eee, aaa, X[14], 7); + III(aaa, bbb, ccc, ddd, eee, X[15], 7); + III(eee, aaa, bbb, ccc, ddd, X[ 8], 12); + III(ddd, eee, aaa, bbb, ccc, X[12], 7); + III(ccc, ddd, eee, aaa, bbb, X[ 4], 6); + III(bbb, ccc, ddd, eee, aaa, X[ 9], 15); + III(aaa, bbb, ccc, ddd, eee, X[ 1], 13); + III(eee, aaa, bbb, ccc, ddd, X[ 2], 11); + + /* parallel round 3 */ + HHH(ddd, eee, aaa, bbb, ccc, X[15], 9); + HHH(ccc, ddd, eee, aaa, bbb, X[ 5], 7); + HHH(bbb, ccc, ddd, eee, aaa, X[ 1], 15); + HHH(aaa, bbb, ccc, ddd, eee, X[ 3], 11); + HHH(eee, aaa, bbb, ccc, ddd, X[ 7], 8); + HHH(ddd, eee, aaa, bbb, ccc, X[14], 6); + HHH(ccc, ddd, eee, aaa, bbb, X[ 6], 6); + HHH(bbb, ccc, ddd, eee, aaa, X[ 9], 14); + HHH(aaa, bbb, ccc, ddd, eee, X[11], 12); + HHH(eee, aaa, bbb, ccc, ddd, X[ 8], 13); + HHH(ddd, eee, aaa, bbb, ccc, X[12], 5); + HHH(ccc, ddd, eee, aaa, bbb, X[ 2], 14); + HHH(bbb, ccc, ddd, eee, aaa, X[10], 13); + HHH(aaa, bbb, ccc, ddd, eee, X[ 0], 13); + HHH(eee, aaa, bbb, ccc, ddd, X[ 4], 7); + HHH(ddd, eee, aaa, bbb, ccc, X[13], 5); + + /* parallel round 4 */ + GGG(ccc, ddd, eee, aaa, bbb, X[ 8], 15); + GGG(bbb, ccc, ddd, eee, aaa, X[ 6], 5); + GGG(aaa, bbb, ccc, ddd, eee, X[ 4], 8); + GGG(eee, aaa, bbb, ccc, ddd, X[ 1], 11); + GGG(ddd, eee, aaa, bbb, ccc, X[ 3], 14); + GGG(ccc, ddd, eee, aaa, bbb, X[11], 14); + GGG(bbb, ccc, ddd, eee, aaa, X[15], 6); + GGG(aaa, bbb, ccc, ddd, eee, X[ 0], 14); + GGG(eee, aaa, bbb, ccc, ddd, X[ 5], 6); + GGG(ddd, eee, aaa, bbb, ccc, X[12], 9); + GGG(ccc, ddd, eee, aaa, bbb, X[ 2], 12); + GGG(bbb, ccc, ddd, eee, aaa, X[13], 9); + GGG(aaa, bbb, ccc, ddd, eee, X[ 9], 12); + GGG(eee, aaa, bbb, ccc, ddd, X[ 7], 5); + GGG(ddd, eee, aaa, bbb, ccc, X[10], 15); + GGG(ccc, ddd, eee, aaa, bbb, X[14], 8); + + /* parallel round 5 */ + FFF(bbb, ccc, ddd, eee, aaa, X[12] , 8); + FFF(aaa, bbb, ccc, ddd, eee, X[15] , 5); + FFF(eee, aaa, bbb, ccc, ddd, X[10] , 12); + FFF(ddd, eee, aaa, bbb, ccc, X[ 4] , 9); + FFF(ccc, ddd, eee, aaa, bbb, X[ 1] , 12); + FFF(bbb, ccc, ddd, eee, aaa, X[ 5] , 5); + FFF(aaa, bbb, ccc, ddd, eee, X[ 8] , 14); + FFF(eee, aaa, bbb, ccc, ddd, X[ 7] , 6); + FFF(ddd, eee, aaa, bbb, ccc, X[ 6] , 8); + FFF(ccc, ddd, eee, aaa, bbb, X[ 2] , 13); + FFF(bbb, ccc, ddd, eee, aaa, X[13] , 6); + FFF(aaa, bbb, ccc, ddd, eee, X[14] , 5); + FFF(eee, aaa, bbb, ccc, ddd, X[ 0] , 15); + FFF(ddd, eee, aaa, bbb, ccc, X[ 3] , 13); + FFF(ccc, ddd, eee, aaa, bbb, X[ 9] , 11); + FFF(bbb, ccc, ddd, eee, aaa, X[11] , 11); + + /* combine results */ + ddd += cc + MDbuf[1]; /* final result for MDbuf[0] */ + MDbuf[1] = MDbuf[2] + dd + eee; + MDbuf[2] = MDbuf[3] + ee + aaa; + MDbuf[3] = MDbuf[4] + aa + bbb; + MDbuf[4] = MDbuf[0] + bb + ccc; + MDbuf[0] = ddd; + + return; +} + +/********************************************************************/ + +void MDfinish(dword *MDbuf, byte *strptr, dword lswlen, dword mswlen) +{ + unsigned int i; /* counter */ + dword X[16]; /* message words */ + + memset(X, 0, 16*sizeof(dword)); + + /* put bytes from strptr into X */ + for (i=0; i<(lswlen&63); i++) { + /* byte i goes into word X[i div 4] at pos. 8*(i mod 4) */ + X[i>>2] ^= (dword) *strptr++ << (8 * (i&3)); + } + + /* append the bit m_n == 1 */ + X[(lswlen>>2)&15] ^= (dword)1 << (8*(lswlen&3) + 7); + + if ((lswlen & 63) > 55) { + /* length goes to next block */ + compress(MDbuf, X); + memset(X, 0, 16*sizeof(dword)); + } + + /* append length in bits*/ + X[14] = lswlen << 3; + X[15] = (lswlen >> 29) | (mswlen << 3); + compress(MDbuf, X); + + return; +} + +/************************ end of file rmd160.c **********************/ + diff --git a/rmd160.h b/rmd160.h new file mode 100644 index 0000000..8e84bb5 --- /dev/null +++ b/rmd160.h @@ -0,0 +1,125 @@ +/* + * $Header: /home/sater/bridge/bigdeal/RCS/rmd160.h,v 1.3 1999/12/11 09:42:38 sater Exp $ + */ + +/********************************************************************\ + * + * FILE: rmd160.h + * + * CONTENTS: Header file for a sample C-implementation of the + * RIPEMD-160 hash-function. + * TARGET: any computer with an ANSI C compiler + * + * AUTHOR: Antoon Bosselaers, ESAT-COSIC + * DATE: 1 March 1996 + * VERSION: 1.0 + * + * Copyright (c) Katholieke Universiteit Leuven + * 1996, All Rights Reserved + * +\********************************************************************/ + +#ifndef RMD160H /* make sure this file is read only once */ +#define RMD160H + +/********************************************************************/ + +/* macro definitions */ + +/* collect four bytes into one word: */ +#define BYTES_TO_DWORD(strptr) \ + (((dword) *((strptr)+3) << 24) | \ + ((dword) *((strptr)+2) << 16) | \ + ((dword) *((strptr)+1) << 8) | \ + ((dword) *(strptr))) + +/* ROL(x, n) cyclically rotates x over n bits to the left */ +/* x must be of an unsigned 32 bits type and 0 <= n < 32. */ +#define ROL(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* the five basic functions F(), G() and H() */ +#define F(x, y, z) ((x) ^ (y) ^ (z)) +#define G(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define H(x, y, z) (((x) | ~(y)) ^ (z)) +#define I(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define J(x, y, z) ((x) ^ ((y) | ~(z))) + +/* the ten basic operations FF() through III() */ +#define FF(a, b, c, d, e, x, s) {\ + (a) += F((b), (c), (d)) + (x);\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define GG(a, b, c, d, e, x, s) {\ + (a) += G((b), (c), (d)) + (x) + 0x5a827999UL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define HH(a, b, c, d, e, x, s) {\ + (a) += H((b), (c), (d)) + (x) + 0x6ed9eba1UL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define II(a, b, c, d, e, x, s) {\ + (a) += I((b), (c), (d)) + (x) + 0x8f1bbcdcUL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define JJ(a, b, c, d, e, x, s) {\ + (a) += J((b), (c), (d)) + (x) + 0xa953fd4eUL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define FFF(a, b, c, d, e, x, s) {\ + (a) += F((b), (c), (d)) + (x);\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define GGG(a, b, c, d, e, x, s) {\ + (a) += G((b), (c), (d)) + (x) + 0x7a6d76e9UL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define HHH(a, b, c, d, e, x, s) {\ + (a) += H((b), (c), (d)) + (x) + 0x6d703ef3UL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define III(a, b, c, d, e, x, s) {\ + (a) += I((b), (c), (d)) + (x) + 0x5c4dd124UL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } +#define JJJ(a, b, c, d, e, x, s) {\ + (a) += J((b), (c), (d)) + (x) + 0x50a28be6UL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10);\ + } + +/********************************************************************/ + +/* function prototypes */ + +void MDinit(dword *MDbuf); +/* + * initializes MDbuffer to "magic constants" + */ + +void compress(dword *MDbuf, dword *X); +/* + * the compression function. + * transforms MDbuf using message bytes X[0] through X[15] + */ + +void MDfinish(dword *MDbuf, byte *strptr, dword lswlen, dword mswlen); +/* + * puts bytes from strptr into X and pad out; appends length + * and finally, compresses the last block(s) + * note: length in bits == 8 * (lswlen + 2^32 mswlen). + * note: there are (lswlen mod 64) bytes left in strptr. + */ + +#endif /* RMD160H */ + +/*********************** end of file rmd160.h ***********************/ + diff --git a/test.c b/test.c new file mode 100644 index 0000000..e80a7d1 --- /dev/null +++ b/test.c @@ -0,0 +1,678 @@ +#include +#include +#include + +#include "types.h" +#include "rmd160.h" +#include "bigdeal.h" +#include "mp.h" +#include "binomial.h" +#include "output.h" +#include "os.h" +#include "collect.h" + +static char rcsid[] = "$Header: /home/sater/bridge/bigdeal/RCS/main.c,v 1.26 2000/09/08 05:13:44 sater Exp $"; + +#define MESSLEN 100 /* Length of input buffer(s) */ +#define ENTROPY_TO_COLLECT RMDsize*4/3 /* 33% extra safety/paranoia */ + +progparams_t parameters; /* Program parameters go in here */ +FILE *flog; /* Not used in safe version */ + +static int +readline(FILE *ifile, char *buf, int len) +/* + * Read line into buf + * Check for length, discard trailing \n + */ +{ + char *eol; + + if(fgets(buf, len, ifile) == NULL) + return 0; + eol = strchr(buf, '\n'); + if (eol) + *eol = 0; + return 1; +} + +/* + * Section that handles initialization file + * Currently in use for hand format(s) + * + * File contains keyword=value lines + * The init_file[] array contains default values, overwritten by file + */ + +static char init_header[] = "[BigDeal]"; + +char default_formats[MESSLEN] = "dup,pbn"; +char default_askformats[MESSLEN] = "no"; +char default_owner[MESSLEN] = "Identification of owner or tournament"; + +#define LONGESTKEYWORD 20 /* Extra bytes to read for keyword and = */ +struct ifrecord { + char *if_keyword; + char *if_value; +} init_file[] = { + { "formats", default_formats }, + { "askformats", default_askformats }, + { "owner", default_owner }, + { 0 } +}; + +void +write_init_file(char *ifname) +/* + * Prompt for defaults, and write init_file + */ +{ + FILE *ifile; + char buf1[MESSLEN], buf2[MESSLEN]; + struct ifrecord *ifrp; + + printf("This program can generate various hand formats, one or more per run:\n\n"); + output_help(); + do { + printf("Give comma separated list of formats usually desired: [%s] ", + default_formats); + readline(stdin, buf1, MESSLEN); + if (buf1[0] == 0) + strcpy(buf1, default_formats); + strcpy(buf2, buf1); + } while (output_specify_formats(buf2, 0)==0); + strcpy(default_formats, buf1); + + printf("\nNormally you will always use the format(s) just specified,\n"); + printf("but maybe you would like to change it for some runs.\n"); + printf("Do you want the program to reconfirm the format every run? [%s] ", default_askformats); + readline(stdin, buf1, MESSLEN); + if (buf1[0]) + strcpy(default_askformats, buf1[0] == 'y' ? "yes" : "no"); + + printf("\nIf you give an identification string the program will ensure\n"); + printf("that nobody with a different identification can generate the\n"); + printf("same sets of deals as you\n"); + printf("identication? [%s]\n? ", default_owner); + readline(stdin, buf1, MESSLEN); + if (buf1[0]) + strcpy(default_owner, buf1); + + ifile = fopen(ifname, "w"); + fprintf(ifile, "%s\n", init_header); + for (ifrp=init_file; ifrp->if_keyword; ifrp++) { + fprintf(ifile, "%s=%s\n", ifrp->if_keyword, ifrp->if_value); + } + fclose(ifile); +} + +void +read_init_file(char *ifname, int write_when_absent) +/* + * Read init file + */ +{ + FILE *ifile; + char buf[MESSLEN+LONGESTKEYWORD]; + char *eqptr; + struct ifrecord *ifrp; + + ifile = fopen(ifname, "r"); + if (ifile == NULL) { + if (write_when_absent) + write_init_file(ifname); + return; + } + while (readline(ifile, buf, MESSLEN+LONGESTKEYWORD)) { + if (buf[0] == 0) + continue; /* empty line */ + if (strcmp(buf, init_header)==0) + continue; /* header for Windows routines */ + if (buf[0] == '[') + break; /* end of our stuff */ + eqptr = strchr(buf, '='); + if (eqptr == 0) { + fprintf(stderr, "Line '%s' does not contain =\n", buf); + fprintf(stderr, "Suggest rerun program with -R flag\n"); + continue; + } + *eqptr++ = 0; + for (ifrp=init_file; ifrp->if_keyword; ifrp++) { + if (strcmp(ifrp->if_keyword, buf)==0) { + strcpy(ifrp->if_value, eqptr); + break; + } + } + if (!ifrp->if_keyword) { + fprintf(stderr, "Keyword %s in init_file unknown\n", buf); + fprintf(stderr, "Suggest rerun program with -R flag\n"); + } + } + fclose(ifile); +} + +#ifndef BIGDEALX +/* + * All parameters for the program when it is running in binary or safe mode + * In this mode the program should be as idiot proof as possible + */ +#define OPTION_STRING "f:n:p:R" +#define USAGE_STRING "[-n number-of-deals] [-p outputfile-prefix] [-f output-format-list] [-R(re-init)]" +#define MAXDEALS 100 /* No more than 100 deals in standard prog */ +#define VERSION_COMMENT "" + +#else /* BIGDEALX */ +/* + * Parameters for the other mode. This is the hacker mode where the user + * can tinkle with entropy and other operations that increase the likelyhood + * of the program generating something else than a random, never occurred + * before set of deals. + */ +#define OPTION_STRING "e:E:f:h:n:op:R" +#define USAGE_STRING "[-n nr-of-deals] [-p ofile-prefx] [-f o-format-list] [-e entropy-str] [-E entropy-file] [-o(only entropy from command line)] [-h hash] [-R(re-init)]" +#define MAXDEALS 1000000000 +#define VERSION_COMMENT "(Extended version, not recommended for tournament use)" + +#define HISTNAME "dealentr.txt" +#define LOGNAME "deallog.txt" + +/* + **************************************************************************** + * Begin section of code for other mode only + **************************************************************************** + */ + +static void +checkduphash(char *hash) +/* + * Paranoia function: if in test we ever run into the same 160 bit number again + * it is time to reevaluate our assumptions + */ +{ + FILE *fhist; + char oldhash[MESSLEN]; + int hashlen; + int counter, badentry; + + hashlen = strlen(hash); + fhist = fopen(HISTNAME, "a+"); + if (fhist == NULL) { + fprintf(stderr, "Couldn't open %s\n", HISTNAME); + return; + } + counter = 0; + badentry = 0; + fseek(fhist, 0L, 0); + while (readline(fhist, oldhash, MESSLEN)) { + if (strlen(oldhash) != hashlen) { + badentry++; + continue; + } + if (strcmp(oldhash, hash) == 0) { + fprintf(flog, "Panic: same hash, index %d\n", counter); + fprintf(stderr, "Panic: same hash, index %d\n", counter); + exit(-1); + } + counter++; + } + fprintf(fhist, "%s\n", hash); + fclose(fhist); + fprintf(flog, "Checked hash against %d previous hashes\n", counter); + if (badentry) { + fprintf(flog, "The file %s contained %d bad entries\n", + HISTNAME, badentry); + } +} + +static void +read_entropy_from_file(char *fname) +/* + * A frontend has generated entropy for us. + * Let us hope it did the right thing. + * We give it credit for 4 bits entropy per byte. + */ +{ + FILE *fentr; + int c; + + if (fname == 0) { + fprintf(stderr, "No entropy file supplied\n"); + return; + } + fentr = fopen(fname, "r"); + if (fentr == NULL) { + fprintf(stderr, "Cannot open %s\n", fname); + return; + } + while ((c = getc(fentr)) >= 0) { + collect_more((byte *) &c, sizeof(c), 4); + } + fclose(fentr); +} + +static int +hexval(char c) +/* + * Convert characters '0'..'9', 'A'..'F' and 'a'..'f' to 0..15 + */ +{ + + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + fprintf(stderr, "Character %c is not a hexchar\n", c); + exit(-1); +} + +static void +random_set(char *hashstr, byte *sr) +/* + * hashstr is a 40 byte string of hex characters + * we convert it into a 20 byte(160 bit) binary value + */ +{ + int i; + + if (strlen(hashstr) != 2*RMDbytes) { + fprintf(stderr, "Argument %s should be %d characters long\n", + hashstr, 2*RMDbytes); + exit(-1); + } + for (i=0; i=64; nbytes-=64) { + for (i=0; i<16; i++) { + X[i] = BYTES_TO_DWORD(value); + value += 4; + } + compress(MDbuf, X); + } + + /* finish: */ + MDfinish(MDbuf, value, length, 0); + + for (i=0; i>2]; /* implicit cast to byte */ + hashcode[i+1] = (MDbuf[i>>2] >> 8); /* extracts the 8 least */ + hashcode[i+2] = (MDbuf[i>>2] >> 16); /* significant bits. */ + hashcode[i+3] = (MDbuf[i>>2] >> 24); + } + + return (byte *)hashcode; +} + +static int +goedel(dl_num *dnp) +/* + * Checks whether the contents of dnp is a number less than the number + * of bridge deals. + */ +{ + /* + * This number is precomputed + */ + static byte nr_bridge_deals[L] = + { 173,85,227,21,99,77,218,101,139,244,146,0}; + +#ifdef BIGDEALX + byte a[L], b[L]; + + n_over_k(52,13,a); + n_over_k(39,13,b); + mp96_mul(a,a,b); + n_over_k(26,13,b); + mp96_mul(a,a,b); + + /* + * This gives a the value of the number of bridge deals + * =( (52 over 13) times (39 over 13) times (26 over 13) ) + * Now let us check our internal calculations + * + * If it is wrong we miscalculated somewhere + */ + + if (mp96_cmp(a, nr_bridge_deals) != 0) { + fprintf(stderr, "Miscalculation\n"); + /* + * print_goedel(stderr, (dl_num*) a); + * print_goedel(stderr, (dl_num*) nr_bridge_deals); + */ + exit(-1); + } +#endif + + if (mp96_cmp(dnp->dn_num, nr_bridge_deals) >= 0) + return 0; /* too big, not a hand number */ + return 1; +} + +extern int nrandombits; + +static void +get_entropy_from_keyboard() { + int c, oldc; + int nbits; + + cbreak(); + printf("Type random characters until you are told to stop "); + oldc = 0; + do { + c = getchtm(&nbits); + if (c != oldc) { + /* + * Collect the character, assume 2 bits entropy + * plus what the timing supplied. + */ + collect_more( (byte*)&c, sizeof(c), 2+nbits); + oldc = c; + } + } while (nrandombits < ENTROPY_TO_COLLECT); + printf("\nThat is enough\007\n"); + cooked(); +} + +#ifdef BIGDEALX +char * +hexdump(byte *input, int len) { + int i = 0; + char *output = malloc(2*len+1); + char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + output[len] = 0; + for (i = 0; i < len; i++) { + output[2*i] = hex[input[i] >> 4]; + output[2*i+1] = hex[input[i] & 0x0F]; + } + return output; +} +#endif + +/* + * Structure with all values that get hashed for random generation + * This includes hash of owner identication making it impossible for + * another owner to generate the same series of deals + * Reduces 2**-160 chance to zero + */ +static struct { + byte seed_sequence[4]; /* sequence number in PRNG sequence */ + byte seed_random[RMDbytes]; /* 160 bits collected at start */ + byte seed_owner[RMDbytes]; /* 160 bit hash of owner ident */ + byte seed_padding[RMDbytes]; /* padding to 64 bytes */ +} seed; + +int +main (int argc, char *argv[]) +{ + int i; + char message[MESSLEN]; + byte *hashcode; + unsigned long seqno; + dl_num dnumber; + char filename[MESSLEN] = ""; + int c; + extern char *optarg; + char *formats = 0; +#ifdef BIGDEALX + int only_arg_entropy = 0; + char *hashstr = 0; + int dangerous_code_used = 0; +#else +#define only_arg_entropy 0 +#endif + + /* + * Say hi to operator + */ + printf("Big Deal version %d.%d%s\n\n", + VERSION_MAJOR, VERSION_MINOR, VERSION_COMMENT); + +#ifdef BIGDEALX + flog = fopen(LOGNAME, "a"); +#endif + os_start(); + collect_start(); + + while ((c = getopt(argc, argv, OPTION_STRING)) != -1) { + switch(c) { +#ifdef BIGDEALX + case 'E': + read_entropy_from_file(optarg); + dangerous_code_used = 1; + break; + case 'e': + collect_more((byte *) optarg, strlen(optarg), 4*strlen(optarg)); + dangerous_code_used = 1; + break; + case 'h': + hashstr = optarg; + /* fall through */ + case 'o': + only_arg_entropy = 1; + dangerous_code_used = 1; + break; +#endif + case 'p': + strncpy(filename, optarg, MESSLEN-1); + break; + case 'f': + formats = optarg; + break; + case 'n': + parameters.pp_nboards = atoi(optarg); + break; + case 'R': + read_init_file(os_init_file_name(), 0); + write_init_file(os_init_file_name()); + exit(0); + case '?': + fprintf(stderr, "Usage: %s %s\n", argv[0], USAGE_STRING); + exit(-1); + } + } + + if (!only_arg_entropy) + os_collect(); + + read_init_file(os_init_file_name(), 1); + binomial_start(); + /* + * Read number of boards to generate + */ + while(parameters.pp_nboards <= 0 || parameters.pp_nboards > MAXDEALS) { + /* + * If we are asked to generate more than 100 boards refuse + * We only have 160 bits entropy, and no one plays sessions + * of more than 100 boards anyhow + */ + if (parameters.pp_nboards > MAXDEALS) { + parameters.pp_nboards = 0; + printf("The maximum is %d, run program again for more\n", + MAXDEALS); + } + printf("Number of boards to deal(1-%d): ", MAXDEALS); + (void) readline(stdin, message, MESSLEN); + parameters.pp_nboards = atoi(message); + /* + * Collect the string, no entropy assumed + */ + if (!only_arg_entropy) + collect_more( (byte*)message, strlen(message), 0); + } + + /* + * Read part of filename before the . + */ + while(!legal_filename_prefix(filename)) { + printf("Output filename(without suffix): "); + (void) readline(stdin, message, MESSLEN); + /* + * Collect the string, 5 bits entropy assumed + */ + if (!only_arg_entropy) + collect_more( (byte*)message, strlen(message), 5); + strcpy(filename,message); + } + + /* + * Get output formats + */ + if (formats == 0) { + /* + * Not specified on command line + */ + if (strcmp(default_askformats, "yes")==0) { + printf("Hand format(s) to generate: [%s] ", + default_formats); + (void) readline(stdin, message, MESSLEN); + if (message[0]) { + strcpy(default_formats, message); + } + } + formats = default_formats; + } + + /* + * If we do not have enough entropy collected (very likely) + * let the user supply it by rattling his keyboard + */ + if (!only_arg_entropy && nrandombits < ENTROPY_TO_COLLECT) { + get_entropy_from_keyboard(); + } + + + /* + * Extract the entropy into the random part of the seed + */ + collect_finish(seed.seed_random); +#ifdef BIGDEALX + if (nrandombits < ENTROPY_TO_COLLECT) { + /* + * Can only happen when only_arg_entropy is set + */ + printf("WARNING: entropy supplied is dangerously low!!!\n"); + } + if (dangerous_code_used) { + printf("You used features in this extended version of Big Deal\n"); + printf("that might defeat the purpose(generating unique sequences).\n"); + printf("Use hands for actual play only with permission from your national authority.\n\n"); + } + + /* + * Did someone use the -h flag ? + */ + if (hashstr) + random_set(hashstr, seed.seed_random); + + /* + * Start checking for duplicate hashes, and log current hash + */ + for (i=0; i>8) & 0xFF; + seed.seed_sequence[2] = (seqno>>16) & 0xFF; + seed.seed_sequence[3] = (seqno>>24) & 0xFF; + /* + * Run all the bits through the hash + */ + hashcode = RMDhash((byte *) &seed, sizeof(seed)); + /* + * Take the first L bytes(96 bits) as a candidate + * hand number + */ + memcpy(dnumber.dn_num, hashcode, L); + } while(!goedel(&dnumber)); + /* + * Dump the input and the output to STDERR + * Probably should have been done on some command line switch + */ +#ifdef BIGDEALX + fprintf(stderr, "%s %s\n", hexdump((byte *) &seed, sizeof(seed)), hexdump((byte *) hashcode, RMDbytes)); +#endif + /* + * Ok, got one + * Print it in all desired formats + */ + output_hand(i, &dnumber); + } + + /* + * Finished, close output files + */ + output_closefiles(); +#ifdef BIGDEALX + fclose(flog); +#endif + + /* + * Do whatever our OS wants us to do at the end, and then exit + */ + os_finish(); + return 0; +} diff --git a/types.h b/types.h new file mode 100644 index 0000000..9812674 --- /dev/null +++ b/types.h @@ -0,0 +1,10 @@ +/* + * $Header: /home/sater/bridge/bigdeal/RCS/types.h,v 1.2 1999/12/11 09:42:54 sater Exp $ + */ + +typedef unsigned char byte; +typedef unsigned long dword; + +#define RMDsize 160 +#define RMDbytes (RMDsize/8) +#define RMDdwords (RMDsize/32) diff --git a/unix.c b/unix.c new file mode 100644 index 0000000..c87f0d9 --- /dev/null +++ b/unix.c @@ -0,0 +1,177 @@ + +static char rcsid[] = "$Header: /home/sater/bridge/bigdeal/RCS/unix.c,v 1.11 2000/08/25 15:55:53 sater Exp $"; + +#include +#include +#include +#include +#include +#include +#include "types.h" +#include "bigdeal.h" +#include "collect.h" + +extern FILE *flog; + +#ifdef TIOCSETA +/* + * For example on BSDI + */ +#define GTTY TIOCGETA +#define STTY TIOCSETA + +#else +/* + * For example on SunOS + */ + +#define GTTY TCGETS +#define STTY TCSETSF + +#endif /* TIOCSETA */ + +static int subsecbits = 5; +#define MAX_INTERVAL_ENTROPY 6 + +void +gettod(struct timeval *tp) +/* + * Fill in *tp with gettimeofday values + * Side effect: calculate approx precision + */ +{ + int b; + + gettimeofday(tp, (struct timezone *) 0); + /* Find how many bits are set in usec field */ + for(b = 0; b < 20; b++) { + if (tp->tv_usec&(1< subsecbits) { + subsecbits = 20-b; + } +} + +int +getchtm(int *nbits) +/* + * Read one character from standard input + * Time the wait, and use bits for random + * MUST be in cbreak mode for this to work + */ +{ + struct timeval t1, t2; + long sdiff, mdiff; + int c; + long shift; + int b; + + gettod(&t1); + c = getchar(); + gettod(&t2); + mdiff = t2.tv_usec - t1.tv_usec; + sdiff = t2.tv_sec - t1.tv_sec; + if (sdiff > 1000) + sdiff = 1000; + mdiff += sdiff * 1000000; + /* + * Everything slower than 1/8 second can be faked + * Trust at most half of the rest + */ + for (shift = mdiff, b= 0; shift>3 ; shift >>= 2, b++) + ; + if (b <= MAX_INTERVAL_ENTROPY) + *nbits = b; + else + *nbits = MAX_INTERVAL_ENTROPY; + collect_more((byte *) &t1, sizeof(t1), 0); + collect_more((byte *) &t2, sizeof(t2), 0); + if (flog) + fprintf(flog, "Collected character %d, timediff %ld, timebits %d\n", + c, mdiff, *nbits); + return c; +} + +void +os_collect() { + int pid; + struct timeval t; + + pid = getpid(); + /* Trust about 8 bits of randomness in pid */ + collect_more((byte *) &pid, sizeof(pid), 8); + gettod(&t); + /* Trust 6 bits of seconds, and half the subsecond bits */ + collect_more((byte *) &t, sizeof(t), 6+subsecbits/2); + if (flog) + fprintf(flog, "First TOD=(%ld, %ld), subsecbits = %d\n", + t.tv_sec, t.tv_usec, subsecbits); +} + +static struct termios tios; + +void +cbreak() +/* + * Set terminal to state where characters can be read one at a time + * Also disable echo + */ +{ + struct termios newtios; + + newtios = tios; + + /* fiddle newtios */ + newtios.c_lflag &= ~(ICANON|ECHO); + newtios.c_cc[VMIN] = 1; + newtios.c_cc[VTIME] = 0; + ioctl(0, STTY, &newtios); +} + +void +cooked() +/* + * Reset terminal to original state + */ +{ + + ioctl(0, STTY, &tios); +} + +void +os_start() { + + ioctl(0, GTTY, &tios); +} + +void +os_finish() { + + cooked(); +} + +int +legal_filename_prefix(char *s) +/* + * Legal prefix to make legal name when three letter suffix added + */ +{ + + if (*s == 0) /* Too short */ + return 0; + if (strlen(s) > 10) /* Worst case, System V */ + return 0; + while (*s) { + if (*s == '/' || *s == ' ') /* disallow space */ + return 0; + s++; + } + return 1; +} + +char *os_init_file_name() +{ + + return ".bigdealrc"; +} -- cgit v1.2.3