summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoremkael <emkael@tlen.pl>2017-11-25 16:15:54 +0100
committeremkael <emkael@tlen.pl>2017-11-25 16:15:54 +0100
commit3fe24df1237a77549ba64c6331383a9a40aed1de (patch)
treeb211cd82601f5dee34ff934c01129470f5e571ac
Initial BigDeal sources
-rw-r--r--.gitignore1
-rw-r--r--bigdeal.h66
-rw-r--r--binomial.c139
-rw-r--r--binomial.h7
-rw-r--r--collect.c112
-rw-r--r--collect.h3
-rw-r--r--dos.c162
-rw-r--r--main.c655
-rw-r--r--makefile46
-rw-r--r--mingw.c171
-rw-r--r--mp.c133
-rw-r--r--mp.h12
-rw-r--r--os.h8
-rw-r--r--output.c1132
-rw-r--r--output.h5
-rw-r--r--rmd160.c273
-rw-r--r--rmd160.h125
-rw-r--r--test.c678
-rw-r--r--types.h10
-rw-r--r--unix.c177
20 files changed, 3915 insertions, 0 deletions
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 (i<NCARDSPERHAND)
+ min = i;
+ else
+ min = NCARDSPERHAND;
+ for (j=0; j<=min; j++) {
+ if (i==j || j==0)
+ mp96_one(pascal_triangle[i][j]);
+ else
+ mp96_add(pascal_triangle[i][j],
+ pascal_triangle[i-1][j],
+ pascal_triangle[i-1][j-1]);
+ }
+ }
+}
+
+void
+n_over_k(int n, int k, byte *b)
+/*
+ * "Compute" (n over k) in L bytes(96 bits) precision
+ * Actually just read from pascal_triangle
+ *
+ * Result stored into b[]
+ */
+{
+ if (n<=NCARDSPERDECK && k<=NCARDSPERHAND && k<=n)
+ mp96_assign(b, pascal_triangle[n][k]);
+ else
+ mp96_zero(b);
+}
+
+
+void
+code_to_hand(dl_num *dnp, dl_int *dip)
+/*
+ * This function converts a given number to its associated bridge-deal.
+ * Read the file Godel.pdf for an explanation of the code. The
+ * variable-names used in the comments refer to the variable-names
+ * that were used in the pseudo-code in Godel.pdf.
+ */
+{
+ int i,j,a,b;
+ byte c[L];
+ byte g[L];
+ byte tmp1[L],tmp2[L],tmp3[L];
+ int compass;
+
+ /*
+ * set g_{-1} = g
+ */
+ mp96_assign(g, dnp->dn_num);
+
+ for (compass=COMPASS_NORTH; compass<NCOMPASS; compass++) {
+ /*
+ * Computation of an appropriate constant for the given
+ * compass direction. The constant is equal to:
+ * 39_over_13 x 26_over_13 for North,
+ * 26_over_13 for East,
+ * 1 for South.
+ *
+ * Code continues for West who automatically gets 13 zeroes
+ */
+ mp96_one(c);
+ for (i=2; i<=COMPASS_WEST-compass; i++) {
+ n_over_k(i*13, 13, tmp1);
+ mp96_mul(c, tmp1, c);
+ }
+
+ /*
+ * set a_{-1} = 0
+ */
+ a = 0;
+ for (j=0; j<NCARDSPERHAND; j++) {
+ /*
+ * Computation of a_j, x_j and g_j.
+ * a_j is computed by setting variable b to a_{j-1} and
+ * incrementing it until it reaches the value a_j.
+ */
+ n_over_k(13*(NCOMPASS-compass)-a-j, 13-j, tmp1);
+
+ /*
+ * b is set to a_{j-1} and up
+ */
+ for(b=a; ; b++) {
+ n_over_k(13*(NCOMPASS-compass)-b-1-j, 13-j, tmp2);
+ mp96_sub(tmp2, tmp1, tmp2);
+ mp96_mul(tmp2, tmp2, c);
+ /*
+ * Check if b < a_j, i.e. if tmp2 > 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 <stdio.h>
+
+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<RMDbytes; i+=4) {
+ hash[i] = MDbuf[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 <conio.h>
+#include <time.h>
+#include <ctype.h>
+#include <stdio.h>
+#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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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<RMDbytes; i++)
+ sr[i] = hexval(hashstr[2*i+1]) | (hexval(hashstr[2*i])<<4);
+}
+
+/*
+ ****************************************************************************
+ * End section of code for other mode only
+ ****************************************************************************
+ */
+
+#endif /* BIGDEALX */
+
+static byte *
+RMDhash(byte *value, int length)
+/*
+ * Hashes value of length bytes using RIPEMD160
+ *
+ * Returns pointer to 20 bytes hashcode
+ */
+{
+ dword MDbuf[RMDdwords]; /* contains (A, B, C, D(, E)) */
+ dword X[16]; /* current 16 word chunk */
+ static byte hashcode[RMDbytes]; /* for final hash-value */
+ unsigned int i; /* counter */
+ int nbytes; /* bytes not yet processed */
+
+ /* initialize */
+ MDinit(MDbuf);
+
+ /* Process value in 16-word chunks */
+ for (nbytes=length; nbytes>=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<RMDbytes; i+=4) {
+ hashcode[i] = MDbuf[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<RMDbytes; i++) {
+ message[2*i ] = "0123456789ABCDEF"[seed.seed_random[i]/16];
+ message[2*i+1] = "0123456789ABCDEF"[seed.seed_random[i]%16];
+ }
+ message[2*RMDbytes] = 0;
+ if (!hashstr)
+ checkduphash(message); /* If this fails .... */
+
+ fprintf(flog, "Deal %d boards to file %s, hash = %s\n",
+ parameters.pp_nboards, filename, message);
+#endif
+ (void) output_specify_formats(formats, 1);
+ output_createfiles(filename, &parameters);
+
+ /*
+ * Generate a sequence of 160 bit pseudo random numbers
+ * by running the random bits with an increasing
+ * counter through the cryptographical hash.
+ * This according to Carl Ellison's recommendation for P1363
+ *
+ * But first put hash of owner ident into seed
+ */
+ hashcode = RMDhash((byte *) default_owner, strlen(default_owner));
+ memcpy(seed.seed_owner, hashcode, RMDbytes);
+
+ seqno = 0;
+ for(i = 1; i <= parameters.pp_nboards; i++) {
+ /*
+ * Next do loop executed as long as we have the misfortune
+ * to make 96 bit numbers above the number of hands
+ */
+ do {
+ seqno++;
+ /*
+ * The next code guarantees the same sequence on
+ * litle endian and big endian machines, which
+ * makes it possible to reproduce sequences on each
+ */
+ seed.seed_sequence[0] = seqno & 0xFF;
+ seed.seed_sequence[1] = (seqno>>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 <windows.h>
+#include <conio.h>
+#include <time.h>
+#include <ctype.h>
+#include <stdio.h>
+#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 <memory.h>
+
+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<b2, 0 when b1==b2
+ */
+ {
+ int i;
+ int diff;
+
+ for (i=0; i<L; i++) {
+ diff = b1[i] - b2[i];
+ if (diff)
+ return diff;
+ }
+ return 0;
+}
+
+void
+mp96_mul(byte *b,byte *b1,byte *b2)
+/*
+ * Computes b=b1*b2
+ * overflow goes undetected
+ */
+{
+ int i,j;
+ unsigned int h,carry;
+ byte b1copy[L],b2copy[L],bpart[L];
+
+ /*
+ * Make copies of input in case one of the inputs is also output
+ */
+ mp96_assign(b1copy, b1);
+ mp96_assign(b2copy, b2);
+
+ /*
+ * Here if an input is also output the input gets overwritten
+ */
+ mp96_zero(b);
+
+ for (i=L-1; i>=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 <stdio.h>
+#include <string.h>
+
+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; i<NCARDSPERDECK; i++)
+ nextcard[i] = i+1;
+ nextcard[NCARDSPERDECK] = 0;
+
+ /*
+ * Run through the hand converting skip numbers to cards
+ */
+ for (compass=COMPASS_NORTH; compass<=COMPASS_WEST; compass++) {
+ /*
+ * Get to the beginning of all leftover cards
+ */
+ prevcard = 0;
+ card = nextcard[prevcard];
+ /*
+ * Go select the thirteen cards for this hand
+ */
+ for (i=0; i<NCARDSPERHAND; i++) {
+ /*
+ * For the first card use number of skips directly
+ * for all other cards the extra skip compared to
+ * the previous card
+ */
+ if (i==0)
+ skip=dip->di_hand[compass][0];
+ else
+ skip=dip->di_hand[compass][i] -
+ dip->di_hand[compass][i-1];
+ for (skipcnt=0; skipcnt<skip; skipcnt++) {
+ prevcard = card;
+ card = nextcard[card];
+ }
+ dbhp->dh_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; i<count; i++)
+ putc(filler, out);
+}
+
+static void
+out_bri(FILE *out, dl_byh *dbhp)
+/*
+ * Write out the "bri" record, no filler
+ */
+{
+ int compass, i;
+
+ /*
+ * Note the <COMPASS_WEST
+ * In this format only the hands of North, East and South are given
+ * West is left as an exercise for the Duplimate
+ * (West just gets what is left over)
+ */
+ for (compass=COMPASS_NORTH; compass<COMPASS_WEST; compass++)
+ for (i=0; i<NCARDSPERHAND; i++)
+ fprintf(out,"%02d",dbhp->dh_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; i<NCARDSPERHAND; i++) {
+ /*
+ * Get card in this position for player
+ * If it is part of the suit we are working on
+ * (1..13 for spades, upto 40..52 for clubs)
+ * print it.
+ */
+ card = dbhp->dh_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; i<NCARDSPERDECK/2; i++) {
+ c = 'a';
+ c += dbcp->dc_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; i<NCARDSPERDECK; i++)
+ putc('1' + dbcp->dc_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; i<NCOMPASS; i++) {
+ /*
+ * Start at dealer of this hand
+ */
+ compass = (boardno - 1 + i) % NCOMPASS;
+ for (j=0; j<NCARDSPERHAND; j++) {
+ card = dbhp->dh_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; i<MAXDECIMALS; i++) {
+ mp96_mul(powers_of_ten[i], powers_of_ten[i-1], ten);
+ }
+}
+
+/*ARGSUSED*/
+static void
+print_goedel(FILE *out, int boardno, hr_p hrp)
+/*
+ * Write out the internal 96 bit numbers as a decimal number
+ *
+ * Unlikely that anyone would ever want this in real life
+ */
+{
+ dl_num *dnp = hrp->hr_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; compass<NCOMPASS; compass++) {
+ for (i=0; i<NSUIT; i++)
+ suitlength[compass][i] = 0;
+ hcp = 0;
+ for (i=0; i<NCARDSPERHAND; i++) {
+ /*
+ * Note the -1 to convert from 1..52 to 0..51
+ */
+ card = dbhp->dh_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<NSUIT; i++) {
+ length = suitlength[compass][i];
+ if (length > 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; i<decimals; i++)
+ power_of_ten *= 10;
+
+ sum *= power_of_ten;
+ /*
+ * Make sure of proper rounding
+ */
+ sum += divisor/2;
+ result = sum/divisor;
+
+ fprintf(out, "%d", result/power_of_ten);
+ if (decimals) {
+ fprintf(out, ".");
+ for (i=0; i<decimals; i++) {
+ result -= result/power_of_ten*power_of_ten;
+ power_of_ten /= 10;
+ fprintf(out, "%d", result/power_of_ten);
+ }
+ }
+ fprintf(out, "%s", termstr);
+}
+
+static void
+print_stat(FILE *out)
+{
+ int i, length;
+
+ fprintf(out, "Number of deals: %d\n", prparp->pp_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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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<RMDbytes; i++)
+ sr[i] = hexval(hashstr[2*i+1]) | (hexval(hashstr[2*i])<<4);
+}
+
+/*
+ ****************************************************************************
+ * End section of code for other mode only
+ ****************************************************************************
+ */
+
+#endif /* BIGDEALX */
+
+static byte *
+RMDhash(byte *value, int length)
+/*
+ * Hashes value of length bytes using RIPEMD160
+ *
+ * Returns pointer to 20 bytes hashcode
+ */
+{
+ dword MDbuf[RMDdwords]; /* contains (A, B, C, D(, E)) */
+ dword X[16]; /* current 16 word chunk */
+ static byte hashcode[RMDbytes]; /* for final hash-value */
+ unsigned int i; /* counter */
+ int nbytes; /* bytes not yet processed */
+
+ /* initialize */
+ MDinit(MDbuf);
+
+ /* Process value in 16-word chunks */
+ for (nbytes=length; nbytes>=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<RMDbytes; i+=4) {
+ hashcode[i] = MDbuf[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<RMDbytes; i++) {
+ message[2*i ] = "0123456789ABCDEF"[seed.seed_random[i]/16];
+ message[2*i+1] = "0123456789ABCDEF"[seed.seed_random[i]%16];
+ }
+ message[2*RMDbytes] = 0;
+ if (!hashstr)
+ checkduphash(message); /* If this fails .... */
+
+ fprintf(flog, "Deal %d boards to file %s, hash = %s\n",
+ parameters.pp_nboards, filename, message);
+#endif
+ (void) output_specify_formats(formats, 1);
+ output_createfiles(filename, &parameters);
+
+ /*
+ * Generate a sequence of 160 bit pseudo random numbers
+ * by running the random bits with an increasing
+ * counter through the cryptographical hash.
+ * This according to Carl Ellison's recommendation for P1363
+ *
+ * But first put hash of owner ident into seed
+ */
+ hashcode = RMDhash((byte *) default_owner, strlen(default_owner));
+ memcpy(seed.seed_owner, hashcode, RMDbytes);
+
+ seqno = 0;
+ for(i = 1; i <= parameters.pp_nboards; i++) {
+ /*
+ * Next do loop executed as long as we have the misfortune
+ * to make 96 bit numbers above the number of hands
+ */
+ do {
+ seqno++;
+ /*
+ * The next code guarantees the same sequence on
+ * litle endian and big endian machines, which
+ * makes it possible to reproduce sequences on each
+ */
+ seed.seed_sequence[0] = seqno & 0xFF;
+ seed.seed_sequence[1] = (seqno>>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 <sys/termios.h>
+#include <sys/time.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#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<<b))
+ break;
+ }
+ if (20-b > 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";
+}