]> pd.if.org Git - uuid/commitdiff
Initial commit
authorNathan Wagner <nw@hydaspes.if.org>
Wed, 21 Mar 2012 10:17:39 +0000 (03:17 -0700)
committerNathan Wagner <nw@hydaspes.if.org>
Wed, 21 Mar 2012 10:17:39 +0000 (03:17 -0700)
16 files changed:
Makefile [new file with mode: 0644]
hash.h [new file with mode: 0644]
internal.c [new file with mode: 0644]
md5.c [new file with mode: 0644]
pduuid.h [new file with mode: 0644]
postgres/Makefile [new file with mode: 0644]
postgres/README [new file with mode: 0644]
postgres/pduuid--1.0.sql [new file with mode: 0644]
postgres/pduuid.control [new file with mode: 0644]
postgres/purepguuid.sql [new file with mode: 0644]
postgres/uninstall-uuid.sql [new file with mode: 0644]
postgres/uuid.c [new file with mode: 0644]
rng.c [new file with mode: 0644]
sha1.c [new file with mode: 0644]
tomcrypt_macros.h [new file with mode: 0644]
uuidgen.c [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..1b1c6bb
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,35 @@
+# Makefile for uuid library
+# written by nathan wagner and placed in the public domain
+
+OBJ    = md5.o sha1.o rng.o internal.o
+CC=gcc
+
+# set the following for windows
+#LDFLAGS += -liphlpapi
+
+all:   uuidgen
+
+windows:       libpduuid.a uuidgen.o
+       gcc $(CFLAGS) -Wall -L. -o $@ uuidgen.o -lpduuid $(LDFLAGS) -liphlpapi
+
+libpduuid.a:   $(OBJ)
+       ar rcuv $@ $+
+       ranlib $@
+
+md5.o: md5.c
+       gcc $(CFLAGS) -Wall -fPIC -DLTC_SMALL_CODE -c -o $@ $+
+
+sha1.o:        sha1.c
+       gcc $(CFLAGS) -Wall -fPIC -DLTC_SMALL_CODE -c -o $@ $+
+
+rng.o: rng.c
+       gcc $(CFLAGS) -Wall -fPIC -c -o $@ $+
+
+internal.o:    internal.c
+       gcc $(CFLAGS) -Wall -fPIC -c -o $@ $+
+
+uuidgen:       libpduuid.a uuidgen.o
+       gcc $(CFLAGS) -Wall -L. -o $@ uuidgen.o -lpduuid $(LDFLAGS)
+
+clean:
+       rm -f *.o *.a uuidgen postgres/*.o postgres/*.so
diff --git a/hash.h b/hash.h
new file mode 100644 (file)
index 0000000..a55397f
--- /dev/null
+++ b/hash.h
@@ -0,0 +1,77 @@
+#include <stdint.h>
+#include <string.h>
+
+typedef uint64_t ulong64;
+typedef uint32_t ulong32;
+
+#define CRYPT_OK 0
+#define CRYPT_INVALID_ARG 1
+#define CRYPT_NOP 2
+#define CRYPT_FAIL_TESTVECTOR 3
+#define XMEMCMP memcmp
+#define LTC_ARGCHK(x)
+
+struct sha1_state {
+    ulong64 length;
+    ulong32 state[5], curlen;
+    unsigned char buf[64];
+};
+
+struct md5_state {
+    ulong64 length;
+    ulong32 state[4], curlen;
+    unsigned char buf[64];
+};
+
+typedef union Hash_state {
+    struct sha1_state   sha1;
+    struct md5_state    md5;
+    void *data;
+} hash_state;
+
+int sha1_init(hash_state * md);
+int sha1_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int sha1_done(hash_state * md, unsigned char *hash);
+int sha1_test(void);
+
+int md5_init(hash_state * md);
+int md5_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int md5_done(hash_state * md, unsigned char *hash);
+int md5_test(void);
+
+/* a simple macro for making hash "process" functions */
+#define HASH_PROCESS(func_name, compress_name, state_var, block_size)                       \
+int func_name (hash_state * md, const unsigned char *in, unsigned long inlen)               \
+{                                                                                           \
+    unsigned long n;                                                                        \
+    int           err;                                                                      \
+    LTC_ARGCHK(md != NULL);                                                                 \
+    LTC_ARGCHK(in != NULL);                                                                 \
+    if (md-> state_var .curlen > sizeof(md-> state_var .buf)) {                             \
+       return CRYPT_INVALID_ARG;                                                            \
+    }                                                                                       \
+    while (inlen > 0) {                                                                     \
+        if (md-> state_var .curlen == 0 && inlen >= block_size) {                           \
+           if ((err = compress_name (md, (unsigned char *)in)) != CRYPT_OK) {               \
+              return err;                                                                   \
+           }                                                                                \
+           md-> state_var .length += block_size * 8;                                        \
+           in             += block_size;                                                    \
+           inlen          -= block_size;                                                    \
+        } else {                                                                            \
+           n = MIN(inlen, (block_size - md-> state_var .curlen));                           \
+           memcpy(md-> state_var .buf + md-> state_var.curlen, in, (size_t)n);              \
+           md-> state_var .curlen += n;                                                     \
+           in             += n;                                                             \
+           inlen          -= n;                                                             \
+           if (md-> state_var .curlen == block_size) {                                      \
+              if ((err = compress_name (md, md-> state_var .buf)) != CRYPT_OK) {            \
+                 return err;                                                                \
+              }                                                                             \
+              md-> state_var .length += 8*block_size;                                       \
+              md-> state_var .curlen = 0;                                                   \
+           }                                                                                \
+       }                                                                                    \
+    }                                                                                       \
+    return CRYPT_OK;                                                                        \
+}
diff --git a/internal.c b/internal.c
new file mode 100644 (file)
index 0000000..0fe6962
--- /dev/null
@@ -0,0 +1,460 @@
+/*
+ * internal functions for uuid library
+ *
+ * written by nathan wagner and placed in the public domain
+ */
+#include <stdint.h>
+#include <sys/time.h>
+#include <stdio.h>
+
+#include "hash.h"
+
+#include "pduuid.h"
+
+#ifdef __linux__
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <linux/if.h>
+#endif
+
+#ifdef __APPLE__
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if_dl.h>
+#include <ifaddrs.h>
+#endif
+
+#ifdef WIN32
+#include <windows.h>
+#include <iphlpapi.h>
+#endif
+
+#ifdef __CYGWIN__
+#include <windows.h>
+#include <iphlpapi.h>
+#endif
+
+static void set_time_low(pd_uuid_t *u, uint32_t low) {
+       u->data[0] = (low >> 24) & 0xff;
+       u->data[1] = (low >> 16) & 0xff;
+       u->data[2] = (low >> 8) & 0xff;
+       u->data[3] = low & 0xff;
+}
+
+static void set_time_mid(pd_uuid_t *u, uint16_t mid) {
+       u->data[4] = (mid >> 8) & 0xff;
+       u->data[5] = mid & 0xff;
+}
+
+static void set_time_hi(pd_uuid_t *u, uint16_t hi) {
+       u->data[7] = hi & 0xff;
+       u->data[6] &= 0xf0;
+       u->data[6] |= (hi >> 8) & 0xf;
+}
+
+static void set_version(pd_uuid_t *u, uint8_t version) {
+       u->data[6] &= 0xf;
+       u->data[6] |= (version & 0xf) << 4;
+}
+
+static void set_clock_seq_low(pd_uuid_t *u, uint8_t low) {
+       u->data[9] = low & 0xff;
+}
+
+static void set_clock_seq_hi(pd_uuid_t *u, uint8_t hi) {
+       u->data[8] &= 0xc0;
+       u->data[8] |= hi & 0x3f;
+}
+
+static void set_reserved(pd_uuid_t *u, uint8_t reserved) {
+       u->data[8] &= 0x3f;
+       u->data[8] |= (reserved & 0x3) << 6;
+}
+
+#if 0
+static void set_node(pd_uuid_t *u, uint8_t data[6]) {
+       u->data[10] = data[0];
+       u->data[11] = data[1];
+       u->data[12] = data[2];
+       u->data[13] = data[3];
+       u->data[14] = data[4];
+       u->data[15] = data[5];
+}
+#endif
+
+static void set_node64(pd_uuid_t *u, uint64_t node) {
+       u->data[10] = (node >> 40) & 0xff;
+       u->data[11] = (node >> 32) & 0xff;
+       u->data[12] = (node >> 24) & 0xff;
+       u->data[13] = (node >> 16) & 0xff;
+       u->data[14] = (node >> 8) & 0xff;
+       u->data[15] = (node >> 0) & 0xff;
+}
+
+static void set_timestamp(pd_uuid_t *u, uint64_t ts) {
+       set_time_low(u, ts & 0xffffffff);
+       set_time_mid(u, (ts >> 32) & 0xffff);
+       set_time_hi(u, (ts >> 48) & 0xfff);
+}
+
+static void set_clockseq(pd_uuid_t *u, uint16_t seq) {
+       set_clock_seq_low(u, seq & 0xff);
+       set_clock_seq_hi(u, (seq >> 8) & 0xff);
+}
+
+static void format_uuid(pd_uuid_t *u, struct pd_uuid_state *s, int version) {
+       set_timestamp(u, s->timestamp);
+       set_version(u, version);
+       set_clockseq(u, s->clock_sequence);
+       set_reserved(u, 0x2);
+       set_node64(u, s->node);
+}
+
+static int obtain_global_lock(void *data) {
+       /* no-op */
+       return 0;
+}
+
+static int release_global_lock(void *data) {
+       /* no-op */
+       return 0;
+}
+
+#define GREGORIAN 122192928000000000ULL
+static uint64_t current_time(void) {
+       uint64_t now;
+       struct timeval tv;
+       
+       /* TODO is this BSD specific? */
+       gettimeofday(&tv, 0);
+
+       now = (tv.tv_sec * 10000000ULL + tv.tv_usec * 10ULL) + GREGORIAN;
+       return now;
+}
+
+static void random_bytes(void *buf, size_t n) {
+       unsigned char *s = buf;
+       int i = 0;
+
+       while (i < n) {
+               i += pd_uuid_rng_get_bytes(s+i, n-i);
+       }
+}
+
+static uint64_t random_mc_mac(struct pd_uuid_state  *s) {
+       uint64_t node = 0;
+
+       if (s && s->random_bytes) {
+               s->random_bytes(&node, sizeof node, s->rng_state);
+       } else {
+               random_bytes(&node, sizeof node);
+       }
+       node |= 0x800000000000ULL; /* rfc 4.5 */
+       return node;
+}
+
+/*
+ * TODO would probably make more sense to use a destination array
+ * rather than returning an integer
+ */
+static uint64_t current_node(struct pd_uuid_state *st) {
+       uint64_t node = 0;
+
+#ifdef __linux__
+       struct ifconf   conf;
+       struct ifreq    *req;
+       struct ifreq    interfaces[4];
+       int s, i;
+       unsigned char *data;
+
+       s = socket(AF_INET, SOCK_DGRAM, 0);
+       if (s != -1) {
+               conf.ifc_len = sizeof interfaces;
+               conf.ifc_req = interfaces;
+               if (ioctl(s, SIOCGIFCONF, &conf) == 0)  {
+                       for (i=0; i < 4; i++) {
+                               req = &conf.ifc_req[i];
+                               if (ioctl(s, SIOCGIFFLAGS, req) != 0) {
+                                       continue;
+                               }
+                               if (req->ifr_flags & IFF_LOOPBACK) {
+                                       continue;
+                               }
+                               if (req->ifr_flags & IFF_NOARP) {
+                                       continue;
+                               }
+                               if (ioctl(s, SIOCGIFHWADDR, req) == 0) {
+                                       int j;
+                                       data = (unsigned char *)req->ifr_hwaddr.sa_data;
+                                       node = data[0];
+                                       node = node << 8; node += data[1];
+                                       node = node << 8; node += data[2];
+                                       node = node << 8; node += data[3];
+                                       node = node << 8; node += data[4];
+                                       node = node << 8; node += data[5];
+                                       return node;
+                               }
+                       }
+               }
+       }
+#endif
+
+       /* this is any BSD based system i think */
+#ifdef __APPLE__
+       struct ifaddrs *addrs;
+       struct ifaddrs *a;
+       struct sockaddr_dl *dl;
+       unsigned char *data;
+       if (getifaddrs(&addrs) == 0) {
+               for (a = addrs; a; a = a->ifa_next) {
+
+                       if (a->ifa_addr && a->ifa_addr->sa_family == AF_LINK) {
+                               dl = (struct sockaddr_dl *)a->ifa_addr;
+                               data = (unsigned char *)(dl->sdl_data + dl->sdl_nlen);
+                               if (dl->sdl_alen != 6) continue;
+
+                               node = data[0];
+                               node = node << 8; node += data[1];
+                               node = node << 8; node += data[2];
+                               node = node << 8; node += data[3];
+                               node = node << 8; node += data[4];
+                               node = node << 8; node += data[5];
+                               freeifaddrs(addrs);
+                               return node;
+                       }
+               }
+               freeifaddrs(addrs);
+       }
+#endif
+
+#if defined(WIN32) || defined(__CYGWIN__)
+       IP_ADAPTER_INFO addrs[4];
+       DWORD size;
+       int rc;
+       unsigned char *data;
+
+       size = sizeof addrs;
+       rc = GetAdaptersInfo(addrs, &size);
+       if (rc == ERROR_SUCCESS) {
+               PIP_ADAPTER_INFO info;
+               for (info = addrs; info; info = info->Next) {
+                       if (info->Type != MIB_IF_TYPE_ETHERNET) {
+                               continue;
+                       }
+                       data = info->Address;
+                       node = data[0];
+                       node = node << 8; node += data[1];
+                       node = node << 8; node += data[2];
+                       node = node << 8; node += data[3];
+                       node = node << 8; node += data[4];
+                       node = node << 8; node += data[5];
+               }
+               return node;
+       }
+#endif
+
+       /* if we get here, use a random multicast address */
+       node = random_mc_mac(st);
+       return node;
+}
+
+static uint16_t random_clock_sequence(struct pd_uuid_state *s) {
+       uint16_t seq;
+
+       if (s && s->random_bytes) {
+               s->random_bytes(&seq, sizeof seq, s->rng_state);
+       } else {
+               random_bytes(&seq, sizeof seq);
+       }
+       return seq;
+}
+
+static int read_state(struct pd_uuid_state *s) {
+       s->available = 0;
+       s->node = 0LL;
+       s->clock_sequence = 0;
+       s->timestamp = 0LL;
+
+       return 0;
+}
+
+static int save_state(struct pd_uuid_state *s) {
+       /* no op */
+       return 0;
+}
+
+static unsigned long get_bytes(void *buf, unsigned long n, void *state) {
+       unsigned char *s = buf;
+       int i = 0;
+
+       while (i < n) {
+               i += pd_uuid_rng_get_bytes(s+i, n-i);
+       }
+       return i;
+}
+
+int pd_uuid_init_state(struct pd_uuid_state *s) {
+       if (!s) return 0;
+
+       s->get_lock = obtain_global_lock;
+       s->release_lock = release_global_lock;
+       s->lock_data = 0;
+
+       s->read_state = read_state;
+       s->save_state = save_state;
+
+       s->random_bytes = get_bytes;
+       s->rng_state = 0;
+
+       s->available = 0;
+
+       return 1;
+}
+
+int pd_uuid_make_v1(struct pd_uuid_state *s, pd_uuid_t *uuid) {
+       struct pd_uuid_state    ls;
+       uint64_t        now;
+       uint64_t        node;
+       int err;
+
+       if (!s) {
+               s = &ls;
+               pd_uuid_init_state(s);
+       }
+
+       if (s->get_lock) {
+               if ((err = s->get_lock(s->lock_data)) != 0) {
+                       /* TODO set uuid to nil ? */
+                       /* be cute and have an "error" uuid? */
+                       return 0;
+               }
+       }
+
+       if (s->read_state) {
+               if ((err = s->read_state(s)) != 0) {
+                       return 0;
+               }
+       }
+
+       now = current_time();
+       node = current_node(s);
+
+       if (!s->available || s->node != node) {
+               s->clock_sequence = random_clock_sequence(s);
+       }
+       s->node = node;
+
+       if (s->available && s->timestamp > now) {
+               s->clock_sequence++;
+       } else {
+               s->timestamp = now;
+       }
+
+       if (s->save_state) {
+               if ((err = s->save_state(s)) != 0) {
+                       return 0;
+               }
+       }
+
+       if (s->release_lock) {
+               if ((err = s->release_lock(s->lock_data)) != 0) {
+                       /* TODO set uuid to nil ? */
+                       /* be cute and have an "error" uuid? */
+                       return 0;
+               }
+       }
+
+       format_uuid(uuid, s, 1);
+
+       return 1;
+}
+
+int pd_uuid_make_v1mc(struct pd_uuid_state *ps, pd_uuid_t *uuid) {
+       struct pd_uuid_state    s;
+       uint64_t        now;
+       uint64_t        node;
+
+       obtain_global_lock(0);
+       read_state(&s);
+       now = current_time();
+       node = random_mc_mac(&s);
+       if (!s.available) {
+               s.clock_sequence = random_clock_sequence(&s);
+       }
+
+       if (s.available && s.timestamp > now) {
+               s.clock_sequence++;
+       } else {
+               s.timestamp = now;
+       }
+
+       save_state(&s);
+       release_global_lock(0);
+       s.node = node;
+
+       format_uuid(uuid, &s, 1);
+
+       return 1;
+}
+
+int pd_uuid_make_v4(struct pd_uuid_state *s, pd_uuid_t *uuid) {
+       random_bytes(uuid, sizeof *uuid);
+       set_version(uuid, 4);
+       set_reserved(uuid, 0x2);
+       return 1;
+}
+
+int pd_set_uuid_hash(struct pd_uuid *s, void *hash, int version) {
+       int i;
+       unsigned char *h = hash;
+
+       for (i=0;i<16;i++) {
+               s->data[i] = h[i];
+       }
+       set_version(s, version);
+       set_reserved(s, 0x2);
+       return 1;
+}
+
+int pd_uuid_make_v3(struct pd_uuid_state *s, pd_uuid_t *uuid, pd_uuid_t *ns, void *data, int len) {
+       hash_state hs;
+       unsigned char hash[16];
+
+       md5_init(&hs);
+       md5_process(&hs, ns->data, 16);
+       md5_process(&hs, data, len);
+       md5_done(&hs, hash);
+       pd_set_uuid_hash(uuid, hash, 3);
+       return 1;
+}
+
+int pd_uuid_make_v5(struct pd_uuid_state *s, pd_uuid_t *uuid, pd_uuid_t *ns, void *data, int len) {
+       hash_state hs;
+       unsigned char hash[20];
+
+       sha1_init(&hs);
+       sha1_process(&hs, ns->data, sizeof *ns);
+       sha1_process(&hs, data, len);
+       sha1_done(&hs, hash);
+       pd_set_uuid_hash(uuid, hash, 5);
+       return 1;
+}
+
+int pd_uuid_set_string(pd_uuid_t *uuid, char *s) {
+       unsigned int byte;
+       int i;
+
+       for (i=0;i<16;i++) {
+               if (*s == 0) return 0;
+               if (*s == '-') s++;
+
+               if (sscanf(s, "%02x", &byte) != 1) {
+                       return 0;
+               }
+               s += 2;
+               uuid->data[i] = byte & 0xff;
+       }
+       return 1;
+}
diff --git a/md5.c b/md5.c
new file mode 100644 (file)
index 0000000..7a7652a
--- /dev/null
+++ b/md5.c
@@ -0,0 +1,294 @@
+/*
+ * md5 implementation
+ * adapted from libtomcrypt by Tom St. Denis
+ * by nathan wagner and released into the public domain
+ */
+
+#define ENDIAN_NEUTRAL 1
+#define LTC_SMALL_CODE 1
+
+#include "tomcrypt_macros.h"
+#include "hash.h"
+
+#define F(x,y,z)  (z ^ (x & (y ^ z)))
+#define G(x,y,z)  (y ^ (z & (y ^ x)))
+#define H(x,y,z)  (x^y^z)
+#define I(x,y,z)  (y^(x|(~z)))
+
+#ifdef LTC_SMALL_CODE
+
+#define FF(a,b,c,d,M,s,t) \
+    a = (a + F(b,c,d) + M + t); a = ROL(a, s) + b;
+
+#define GG(a,b,c,d,M,s,t) \
+    a = (a + G(b,c,d) + M + t); a = ROL(a, s) + b;
+
+#define HH(a,b,c,d,M,s,t) \
+    a = (a + H(b,c,d) + M + t); a = ROL(a, s) + b;
+
+#define II(a,b,c,d,M,s,t) \
+    a = (a + I(b,c,d) + M + t); a = ROL(a, s) + b;
+
+static const unsigned char Worder[64] = {
+   0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
+   1,6,11,0,5,10,15,4,9,14,3,8,13,2,7,12,
+   5,8,11,14,1,4,7,10,13,0,3,6,9,12,15,2,
+   0,7,14,5,12,3,10,1,8,15,6,13,4,11,2,9
+};
+
+static const unsigned char Rorder[64] = {
+   7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22,
+   5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,
+   4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,
+   6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21
+};
+
+static const ulong32 Korder[64] = {
+0xd76aa478UL, 0xe8c7b756UL, 0x242070dbUL, 0xc1bdceeeUL, 0xf57c0fafUL, 0x4787c62aUL, 0xa8304613UL, 0xfd469501UL,
+0x698098d8UL, 0x8b44f7afUL, 0xffff5bb1UL, 0x895cd7beUL, 0x6b901122UL, 0xfd987193UL, 0xa679438eUL, 0x49b40821UL,
+0xf61e2562UL, 0xc040b340UL, 0x265e5a51UL, 0xe9b6c7aaUL, 0xd62f105dUL, 0x02441453UL, 0xd8a1e681UL, 0xe7d3fbc8UL,
+0x21e1cde6UL, 0xc33707d6UL, 0xf4d50d87UL, 0x455a14edUL, 0xa9e3e905UL, 0xfcefa3f8UL, 0x676f02d9UL, 0x8d2a4c8aUL,
+0xfffa3942UL, 0x8771f681UL, 0x6d9d6122UL, 0xfde5380cUL, 0xa4beea44UL, 0x4bdecfa9UL, 0xf6bb4b60UL, 0xbebfbc70UL,
+0x289b7ec6UL, 0xeaa127faUL, 0xd4ef3085UL, 0x04881d05UL, 0xd9d4d039UL, 0xe6db99e5UL, 0x1fa27cf8UL, 0xc4ac5665UL,
+0xf4292244UL, 0x432aff97UL, 0xab9423a7UL, 0xfc93a039UL, 0x655b59c3UL, 0x8f0ccc92UL, 0xffeff47dUL, 0x85845dd1UL,
+0x6fa87e4fUL, 0xfe2ce6e0UL, 0xa3014314UL, 0x4e0811a1UL, 0xf7537e82UL, 0xbd3af235UL, 0x2ad7d2bbUL, 0xeb86d391UL
+};
+
+#else
+
+#define FF(a,b,c,d,M,s,t) \
+    a = (a + F(b,c,d) + M + t); a = ROL(a, s) + b;
+
+#define GG(a,b,c,d,M,s,t) \
+    a = (a + G(b,c,d) + M + t); a = ROL(a, s) + b;
+
+#define HH(a,b,c,d,M,s,t) \
+    a = (a + H(b,c,d) + M + t); a = ROL(a, s) + b;
+
+#define II(a,b,c,d,M,s,t) \
+    a = (a + I(b,c,d) + M + t); a = ROL(a, s) + b;
+
+
+#endif   
+
+static int  md5_compress(hash_state *md, unsigned char *buf) {
+    ulong32 i, W[16], a, b, c, d;
+#ifdef LTC_SMALL_CODE
+    ulong32 t;
+#endif
+
+    /* copy the state into 512-bits into W[0..15] */
+    for (i = 0; i < 16; i++) {
+        LOAD32L(W[i], buf + (4*i));
+    }
+    /* copy state */
+    a = md->md5.state[0];
+    b = md->md5.state[1];
+    c = md->md5.state[2];
+    d = md->md5.state[3];
+
+#ifdef LTC_SMALL_CODE
+    for (i = 0; i < 16; ++i) {
+        FF(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]);
+        t = d; d = c; c = b; b = a; a = t;
+    }
+
+    for (; i < 32; ++i) {
+        GG(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]);
+        t = d; d = c; c = b; b = a; a = t;
+    }
+
+    for (; i < 48; ++i) {
+        HH(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]);
+        t = d; d = c; c = b; b = a; a = t;
+    }
+
+    for (; i < 64; ++i) {
+        II(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]);
+        t = d; d = c; c = b; b = a; a = t;
+    }
+
+#else
+    FF(a,b,c,d,W[0],7,0xd76aa478UL)
+    FF(d,a,b,c,W[1],12,0xe8c7b756UL)
+    FF(c,d,a,b,W[2],17,0x242070dbUL)
+    FF(b,c,d,a,W[3],22,0xc1bdceeeUL)
+    FF(a,b,c,d,W[4],7,0xf57c0fafUL)
+    FF(d,a,b,c,W[5],12,0x4787c62aUL)
+    FF(c,d,a,b,W[6],17,0xa8304613UL)
+    FF(b,c,d,a,W[7],22,0xfd469501UL)
+    FF(a,b,c,d,W[8],7,0x698098d8UL)
+    FF(d,a,b,c,W[9],12,0x8b44f7afUL)
+    FF(c,d,a,b,W[10],17,0xffff5bb1UL)
+    FF(b,c,d,a,W[11],22,0x895cd7beUL)
+    FF(a,b,c,d,W[12],7,0x6b901122UL)
+    FF(d,a,b,c,W[13],12,0xfd987193UL)
+    FF(c,d,a,b,W[14],17,0xa679438eUL)
+    FF(b,c,d,a,W[15],22,0x49b40821UL)
+    GG(a,b,c,d,W[1],5,0xf61e2562UL)
+    GG(d,a,b,c,W[6],9,0xc040b340UL)
+    GG(c,d,a,b,W[11],14,0x265e5a51UL)
+    GG(b,c,d,a,W[0],20,0xe9b6c7aaUL)
+    GG(a,b,c,d,W[5],5,0xd62f105dUL)
+    GG(d,a,b,c,W[10],9,0x02441453UL)
+    GG(c,d,a,b,W[15],14,0xd8a1e681UL)
+    GG(b,c,d,a,W[4],20,0xe7d3fbc8UL)
+    GG(a,b,c,d,W[9],5,0x21e1cde6UL)
+    GG(d,a,b,c,W[14],9,0xc33707d6UL)
+    GG(c,d,a,b,W[3],14,0xf4d50d87UL)
+    GG(b,c,d,a,W[8],20,0x455a14edUL)
+    GG(a,b,c,d,W[13],5,0xa9e3e905UL)
+    GG(d,a,b,c,W[2],9,0xfcefa3f8UL)
+    GG(c,d,a,b,W[7],14,0x676f02d9UL)
+    GG(b,c,d,a,W[12],20,0x8d2a4c8aUL)
+    HH(a,b,c,d,W[5],4,0xfffa3942UL)
+    HH(d,a,b,c,W[8],11,0x8771f681UL)
+    HH(c,d,a,b,W[11],16,0x6d9d6122UL)
+    HH(b,c,d,a,W[14],23,0xfde5380cUL)
+    HH(a,b,c,d,W[1],4,0xa4beea44UL)
+    HH(d,a,b,c,W[4],11,0x4bdecfa9UL)
+    HH(c,d,a,b,W[7],16,0xf6bb4b60UL)
+    HH(b,c,d,a,W[10],23,0xbebfbc70UL)
+    HH(a,b,c,d,W[13],4,0x289b7ec6UL)
+    HH(d,a,b,c,W[0],11,0xeaa127faUL)
+    HH(c,d,a,b,W[3],16,0xd4ef3085UL)
+    HH(b,c,d,a,W[6],23,0x04881d05UL)
+    HH(a,b,c,d,W[9],4,0xd9d4d039UL)
+    HH(d,a,b,c,W[12],11,0xe6db99e5UL)
+    HH(c,d,a,b,W[15],16,0x1fa27cf8UL)
+    HH(b,c,d,a,W[2],23,0xc4ac5665UL)
+    II(a,b,c,d,W[0],6,0xf4292244UL)
+    II(d,a,b,c,W[7],10,0x432aff97UL)
+    II(c,d,a,b,W[14],15,0xab9423a7UL)
+    II(b,c,d,a,W[5],21,0xfc93a039UL)
+    II(a,b,c,d,W[12],6,0x655b59c3UL)
+    II(d,a,b,c,W[3],10,0x8f0ccc92UL)
+    II(c,d,a,b,W[10],15,0xffeff47dUL)
+    II(b,c,d,a,W[1],21,0x85845dd1UL)
+    II(a,b,c,d,W[8],6,0x6fa87e4fUL)
+    II(d,a,b,c,W[15],10,0xfe2ce6e0UL)
+    II(c,d,a,b,W[6],15,0xa3014314UL)
+    II(b,c,d,a,W[13],21,0x4e0811a1UL)
+    II(a,b,c,d,W[4],6,0xf7537e82UL)
+    II(d,a,b,c,W[11],10,0xbd3af235UL)
+    II(c,d,a,b,W[2],15,0x2ad7d2bbUL)
+    II(b,c,d,a,W[9],21,0xeb86d391UL)
+#endif
+
+    md->md5.state[0] = md->md5.state[0] + a;
+    md->md5.state[1] = md->md5.state[1] + b;
+    md->md5.state[2] = md->md5.state[2] + c;
+    md->md5.state[3] = md->md5.state[3] + d;
+
+    return CRYPT_OK;
+}
+
+int md5_init(hash_state * md) {
+   md->md5.state[0] = 0x67452301UL;
+   md->md5.state[1] = 0xefcdab89UL;
+   md->md5.state[2] = 0x98badcfeUL;
+   md->md5.state[3] = 0x10325476UL;
+   md->md5.curlen = 0;
+   md->md5.length = 0;
+   return CRYPT_OK;
+}
+
+/**
+   Process a block of memory though the hash
+   @param md     The hash state
+   @param in     The data to hash
+   @param inlen  The length of the data (octets)
+   @return CRYPT_OK if successful
+*/
+HASH_PROCESS(md5_process, md5_compress, md5, 64)
+
+int md5_done(hash_state * md, unsigned char *out) {
+    int i;
+
+    if (md->md5.curlen >= sizeof(md->md5.buf)) {
+       return CRYPT_INVALID_ARG;
+    }
+
+    /* increase the length of the message */
+    md->md5.length += md->md5.curlen * 8;
+
+    /* append the '1' bit */
+    md->md5.buf[md->md5.curlen++] = (unsigned char)0x80;
+
+    /* if the length is currently above 56 bytes we append zeros
+     * then compress.  Then we can fall back to padding zeros and length
+     * encoding like normal.
+     */
+    if (md->md5.curlen > 56) {
+        while (md->md5.curlen < 64) {
+            md->md5.buf[md->md5.curlen++] = (unsigned char)0;
+        }
+        md5_compress(md, md->md5.buf);
+        md->md5.curlen = 0;
+    }
+
+    /* pad upto 56 bytes of zeroes */
+    while (md->md5.curlen < 56) {
+        md->md5.buf[md->md5.curlen++] = (unsigned char)0;
+    }
+
+    /* store length */
+    STORE64L(md->md5.length, md->md5.buf+56);
+    md5_compress(md, md->md5.buf);
+
+    /* copy output */
+    for (i = 0; i < 4; i++) {
+        STORE32L(md->md5.state[i], out+(4*i));
+    }
+    return CRYPT_OK;
+}
+
+int  md5_test(void)
+{
+ #if 0
+    return CRYPT_NOP;
+ #else    
+  static const struct {
+      char *msg;
+      unsigned char hash[16];
+  } tests[] = {
+    { "",
+      { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 
+        0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e } },
+    { "a",
+      {0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8, 
+       0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61 } },
+    { "abc",
+      { 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, 
+        0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 } },
+    { "message digest", 
+      { 0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d, 
+        0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1, 0x61, 0xd0 } }, 
+    { "abcdefghijklmnopqrstuvwxyz",
+      { 0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00, 
+        0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b } },
+    { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+      { 0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5, 
+        0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f } },
+    { "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+      { 0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55, 
+        0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a } }, 
+    { NULL, { 0 } }
+  };
+
+  int i;
+  unsigned char tmp[16];
+  hash_state md;
+
+  for (i = 0; tests[i].msg != NULL; i++) {
+      md5_init(&md);
+      md5_process(&md, (unsigned char *)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+      md5_done(&md, tmp);
+      if (XMEMCMP(tmp, tests[i].hash, 16) != 0) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+  }
+  return CRYPT_OK;
+ #endif
+}
diff --git a/pduuid.h b/pduuid.h
new file mode 100644 (file)
index 0000000..77cbcc1
--- /dev/null
+++ b/pduuid.h
@@ -0,0 +1,40 @@
+#ifndef PD_UUID_H_
+#define PD_UUID_H_ 1
+
+#include <stdint.h>
+
+struct pd_uuid_state {
+       uint64_t        timestamp, node;
+       uint16_t        clock_sequence;
+       int     available;
+       int     (*get_lock)(void *);
+       int     (*release_lock)(void *);
+       void    *lock_data;
+       int     (*read_state)(struct pd_uuid_state *s);
+       int     (*save_state)(struct pd_uuid_state *s);
+       /* TODO hook for a random number generator? */
+       unsigned long (*random_bytes)(void *out, unsigned long outlen,
+                       void *prng_state);
+       void    *rng_state;
+};
+
+struct pd_uuid {
+       uint8_t data[16];
+};
+typedef struct pd_uuid pd_uuid_t;
+
+int pd_uuid_init_state(struct pd_uuid_state *s);
+int pd_uuid_make_v1(struct pd_uuid_state *s, pd_uuid_t *uuid);
+int pd_uuid_make_v1mc(struct pd_uuid_state *s, pd_uuid_t *uuid);
+int pd_uuid_make_v4(struct pd_uuid_state *s, pd_uuid_t *uuid);
+int pd_uuid_make_v3(struct pd_uuid_state *s, pd_uuid_t *uuid, pd_uuid_t *ns, void *data, int len);
+int pd_uuid_make_v5(struct pd_uuid_state *s, pd_uuid_t *uuid, pd_uuid_t *ns, void *data, int len);
+
+int pd_set_uuid_hash(pd_uuid_t *s, void *hash, int version);
+
+int pd_uuid_set_string(pd_uuid_t *uuid, char *s);
+
+unsigned long pd_uuid_rng_get_bytes(unsigned char *out, unsigned long outlen);
+
+
+#endif
diff --git a/postgres/Makefile b/postgres/Makefile
new file mode 100644 (file)
index 0000000..1c24262
--- /dev/null
@@ -0,0 +1,21 @@
+# makefile for postgres uuid type support functions
+# written by nathan wagner and placed in the public domain
+
+EXTENSION=pduuid
+MODULES= pduuid
+DATA= pduuid--1.0.sql
+#DOCS= README.uuid_ossp
+#SHLIB_LINK= -Lpduuid -lpduuid
+MODULE_big= pduuid
+OBJS= uuid.o ../internal.o ../rng.o ../md5.o ../sha1.o
+
+PG_CPPFLAGS := -I..
+PG_CONFIG= pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+#include c:/Program\ Files/PostgreSQL/8.4/lib/pgxs/src/makefiles/pgxs.mk
+
+# uncomment the following on mac
+ifeq ($(PORTNAME), darwin)
+LDFLAGS_SL += -flat_namespace -undefined suppress
+endif
diff --git a/postgres/README b/postgres/README
new file mode 100644 (file)
index 0000000..9d0fd91
--- /dev/null
@@ -0,0 +1,125 @@
+This software package is an addon module for postgres.  It supplies
+support functions for the built-in uuid data type.  It was built and
+tested against postgres version 8.4.0.  This file and all supplied files
+are written by Nathan Wagner and placed in the public domain.  Bug
+reports to nw@hydaspes.if.org.
+
+Credit: the hash functions are stripped down implementations from
+libtomcrypt by Tom St Denis, also in the public domain.
+
+Functions supplied are uuid generation functions, conforming (with
+one exception) to RFC 4122.  The exception lies in the multicast
+bit 
+
+Features:
+
+UUID generation functions for version 1, 3, 4, and 5 UUIDS.
+
+RFC 4122 compliance, with the exception of the multicast bit
+for randomly generated mac addresses.  This module sets the correct
+bit (the most significant bit), rather than the one specified in the RFC
+(the least significant one).
+
+No external library dependency (other than the standard C library).
+The uuid generation has been written from scratch and is included
+with the source.
+
+The entire package is in the public domain, so there are no licensing
+issues.
+
+Compiles with the usual postgres addon infrastructure.
+make
+make install
+psql -f uuid.sql
+psql -f uninstall-uuid.sql
+
+A pure postgres implementation is also supplied of just the generation
+functions in purepguuid.sql.
+
+Generation Functions:
+
+uuid_v1()
+returns a version 1 uuid.  if the mac address can't be determined,
+uses a random one.
+
+uuid_v1mc()
+returns a version 1 uuid using a random mac address
+
+uuid_v3(uuid, text)
+returns a version 3 uuid using the supplied namespace uuid and the
+given input string.  This is an md5 based uuid.
+
+uuid_v4()
+returns a version 4 uuid.  This is a random uuid.  The odds of collision
+are vanishingly low and it is safe to use for regular production uuid
+generation.
+
+uuid_v3(uuid, text)
+returns a version 5 uuid using the supplied namespace uuid and the
+given input string.  This is an sha1 based uuid.
+
+uuid_url(text)
+Returns a version 5 uuid using the URL namespace.
+
+uuid_dns(text)
+Returns a version 5 uuid using the DNS namespace.
+
+uuid_oid(text)
+Returns a version 5 uuid using the DNS namespace.
+
+uuid_x500(text)
+Returns a version 5 uuid using the DNS namespace.
+
+UUID Lookup Functions:
+
+uuid_recent()
+returns the most recent uuid generated by this backend.  Returns
+the nil uuid if no uuids have been generated yet.
+
+uuid_nil()
+Returns the nil uuid (all bits zero).
+
+uuid_ns_dns()
+Returns the DNS namespace uuid.
+6ba7b810-9dad-11d1-80b4-00c04fd430c8
+
+uuid_ns_url()
+Returns the URL namespace uuid.
+6ba7b811-9dad-11d1-80b4-00c04fd430c8
+
+uuid_ns_oid()
+Returns the OID namespace uuid.
+6ba7b812-9dad-11d1-80b4-00c04fd430c8
+
+uuid_ns_x500()
+Returns the X500 namespace uuid.
+6ba7b813-9dad-11d1-80b4-00c04fd430c8
+
+Casting Support:
+
+Cast functions and casts are created for uuids to and from data types
+where this is reasonable:
+
+Bytea: treats the UUID as an array of bytes.  This is always in
+network byte order for the subfields of a uuid, where applicable.
+
+Numeric: treats the UUID as a 128 bit number and converts it to a numeric.
+
+Bit(128) and bit varying: treats the uuid as a 128 bit vector.
+
+Field extraction functions:
+
+uuid_version(uuid)
+Returns an integer corresponding to the 4 bit version number.
+
+uuid_macaddr(uuid)
+Returns a macaddr type corresponding to the mac address part of the
+uuid.  This function can be called on any uuid, not just version 1 uuids.
+
+uuid_timestamp(uuid)
+Returns a timestamp corresponding to the timestamp field in the uuid.  You
+probably want to use uuid_timestamptz().
+
+uuid_timestamptz(uuid)
+Returns a timestamp with time zonecorresponding to the timestamp field in the
+uuid.
diff --git a/postgres/pduuid--1.0.sql b/postgres/pduuid--1.0.sql
new file mode 100644 (file)
index 0000000..68c68eb
--- /dev/null
@@ -0,0 +1,130 @@
+-- uuid support function install script
+-- written by nathan wagner and placed in the public domain
+
+create function uuid_v1() returns uuid as 'pduuid', 'uuid_gen_v1'
+language C strict;
+
+create function uuid_v1mc() returns uuid as 'pduuid', 'uuid_gen_v1_mc'
+language C strict;
+
+create function uuid_v3(uuid, text) returns uuid
+as 'pduuid', 'uuid_gen_v3'
+language C strict;
+
+create function uuid_v4() returns uuid as 'pduuid', 'uuid_gen_v4'
+language C strict;
+
+create function uuid_v5(uuid, text) returns uuid
+as 'pduuid', 'uuid_gen_v5'
+language C strict;
+
+create function uuid_recent() returns uuid as 'pduuid', 'uuid_recent'
+language C strict;
+
+create function uuid_nil() returns uuid as 'pduuid', 'uuid_nil'
+language C strict;
+
+create function uuid_ns_dns() returns uuid as 'pduuid', 'uuid_dns'
+language C strict;
+
+create function uuid_ns_oid() returns uuid as 'pduuid', 'uuid_oid'
+language C strict;
+
+create function uuid_ns_url() returns uuid as 'pduuid', 'uuid_url'
+language C strict;
+
+create function uuid_ns_x500() returns uuid as 'pduuid', 'uuid_x500'
+language C strict;
+
+create function uuid_url(text) returns uuid as $$
+select uuid_v5(uuid_ns_url(), $1);
+$$
+language 'sql' strict;
+
+create function uuid_dns(text) returns uuid as $$
+select uuid_v5(uuid_ns_dns(), $1);
+$$
+language 'sql' strict;
+
+create function uuid_oid(text) returns uuid as $$
+select uuid_v5(uuid_ns_oid(), $1);
+$$
+language 'sql' strict;
+
+create function uuid_x500(text) returns uuid as $$
+select uuid_v5(uuid_ns_x500(), $1);
+$$
+language 'sql' strict;
+
+-- Casts
+
+-- Bytea
+
+create function uuid_bytea_cast(uuid) returns bytea as 
+'uuid', 'uuid_cast_bytea'
+language C strict;
+
+create function uuid_bytea_uncast(bytea) returns uuid as 
+'uuid', 'uuid_cast_from_bytea'
+language C strict;
+
+create cast (uuid as bytea) with function uuid_bytea_cast(uuid);
+
+create cast (bytea as uuid) with function uuid_bytea_uncast(bytea);
+
+-- Numeric
+
+create function uuid_numeric_cast(uuid) returns numeric as 
+'uuid', 'uuid_cast_numeric'
+language C strict;
+
+create function uuid_numeric_uncast(numeric) returns uuid as 
+'uuid', 'uuid_cast_from_numeric'
+language C strict;
+
+create cast (uuid as numeric) with function uuid_numeric_cast(uuid);
+
+create cast (numeric as uuid) with function uuid_numeric_uncast(numeric);
+
+-- Bit and bit varying
+
+create function uuid_bit_cast(uuid) returns bit(128) as 
+'uuid', 'uuid_cast_bit'
+language C strict;
+
+create function uuid_bit_uncast(bit(128)) returns uuid as 
+'uuid', 'uuid_cast_from_bit'
+language C strict;
+
+create cast (uuid as bit(128)) with function uuid_bit_cast(uuid);
+
+create cast (uuid as bit varying) with function uuid_bit_cast(uuid);
+
+create cast (bit(128) as uuid) with function uuid_bit_uncast(bit(128));
+
+create cast (bit varying as uuid) with function uuid_bit_uncast(bit(128));
+
+-- Field extraction functions
+
+create function uuid_version(uuid) returns integer as
+'uuid', 'uuid_extract_version'
+language C strict;
+
+create function uuid_macaddr(uuid) returns macaddr as
+'uuid', 'uuid_extract_macaddr'
+language C strict;
+
+create function uuid_timestamp(uuid) returns timestamp as
+'uuid', 'uuid_extract_timestamp'
+language C strict;
+
+create function uuid_timestamptz(uuid)
+returns timestamp with time zone as
+'uuid', 'uuid_extract_timestamp'
+language C strict;
+
+-- TODO
+-- cast to timestamp / extract timestamp
+-- cast to macaddr / extract macaddr
+-- extract variant
+-- extract clock sequence
diff --git a/postgres/pduuid.control b/postgres/pduuid.control
new file mode 100644 (file)
index 0000000..b49e728
--- /dev/null
@@ -0,0 +1,4 @@
+relocatable = true
+comment = 'Public Domain uuid support functions'
+default_version = '1.0'
+
diff --git a/postgres/purepguuid.sql b/postgres/purepguuid.sql
new file mode 100644 (file)
index 0000000..9e87119
--- /dev/null
@@ -0,0 +1,132 @@
+create or replace function uuid_bytespp(howmany integer) returns bytea as $$
+declare
+       bytes bytea;
+begin
+       bytes = rpad('', howmany);
+
+       for i in 0 .. howmany-1 loop
+               bytes := set_byte(bytes, i, (random()*256)::integer);
+       end loop;
+
+       return bytes;
+end;
+$$ language 'plpgsql';
+
+create or replace function uuid_v1pp() returns uuid as $$
+declare
+       bytes bytea;
+       byte    integer;
+       str     text;
+       id      uuid;
+       tslow   bytea;
+       tsmid   bytea;
+       tshigh  bytea;
+       tsi     bigint;
+begin
+       -- 122192928000000000
+
+       select extract(epoch from now() - '1582-10-15 00:00:00 UTC'::timestamp with time zone)::bigint * 10000000 +
+       extract(microseconds from now() - '1582-10-15 00:00:00 UTC'::timestamp with time zone)::integer % 1000000 * 10
+       into tsi
+       ;
+
+       tslow := decode(lpad(to_hex(tsi & x'ffffffff'::bigint), 8, '0'), 'hex');
+       tsmid := decode(lpad(to_hex((tsi>>32) & x'ffff'::bigint), 4, '0'), 'hex');
+       tshigh := decode(lpad(to_hex((tsi>>48) & x'ffff'::bigint), 4, '0'), 'hex');
+
+       -- we don't store any state, so the clock sequence is random,
+       -- and we don't have any way to get the macaddr, so that's
+       -- random too.  though we set the multicast bit (the real one,
+       -- not the one in the rfc)
+       bytes := tslow || tsmid || tshigh || uuid_bytespp(8);
+
+       byte = get_byte(bytes, 6);
+       byte = (byte & 15) | 16;
+       bytes = set_byte(bytes, 6, byte);
+
+       byte = get_byte(bytes, 8);
+       byte = (byte & 63) | 128;
+       bytes = set_byte(bytes, 8, byte);
+
+       byte = get_byte(bytes, 10);
+       byte = (byte & 127) | 128;
+       bytes = set_byte(bytes, 10, byte);
+
+       str = encode(bytes, 'hex');
+       id = str::uuid;
+       return id;
+end;
+$$ language 'plpgsql';
+
+create or replace function uuid_v4pp() returns uuid as $$
+declare
+       bytes bytea;
+       byte    integer;
+       str     text;
+       id      uuid;
+begin
+       bytes = uuid_bytespp(16);
+
+       byte = get_byte(bytes, 6);
+       byte = (byte & 15) | 64;
+       bytes = set_byte(bytes, 6, byte);
+
+       byte = get_byte(bytes, 8);
+       byte = (byte & 63) | 128;
+       bytes = set_byte(bytes, 8, byte);
+
+       str = encode(bytes, 'hex');
+       id = str::uuid;
+       return id;
+end;
+$$ language 'plpgsql';
+
+create or replace function uuid_v3pp(ns uuid, content bytea) returns uuid as $$
+declare
+       bytes bytea;
+       nsbytes bytea;
+       byte    integer;
+       str     text;
+       id      uuid;
+begin
+       nsbytes = decode(regexp_replace(ns::text, '-', '', 'g'), 'hex');
+       bytes = decode(md5(nsbytes || content), 'hex');
+
+       byte = get_byte(bytes, 6);
+       byte = (byte & 15) | 48;
+       bytes = set_byte(bytes, 6, byte);
+
+       byte = get_byte(bytes, 8);
+       byte = (byte & 63) | 128;
+       bytes = set_byte(bytes, 8, byte);
+
+       str = encode(bytes, 'hex');
+       id = str::uuid;
+       return id;
+end;
+$$ language 'plpgsql';
+
+create or replace function uuid_v5pp(ns uuid, content bytea) returns uuid as $$
+declare
+       bytes bytea;
+       nsbytes bytea;
+       byte    integer;
+       str     text;
+       id      uuid;
+begin
+       nsbytes = decode(regexp_replace(ns::text, '-', '', 'g'), 'hex');
+       bytes = substring(decode(sha1(nsbytes || content), 'hex') from 1 for 16);
+
+       byte = get_byte(bytes, 6);
+       byte = (byte & 15) | 80;
+       bytes = set_byte(bytes, 6, byte);
+
+       byte = get_byte(bytes, 8);
+       byte = (byte & 63) | 128;
+       bytes = set_byte(bytes, 8, byte);
+
+       str = encode(bytes, 'hex');
+       id = str::uuid;
+       return id;
+end;
+$$ language 'plpgsql';
diff --git a/postgres/uninstall-uuid.sql b/postgres/uninstall-uuid.sql
new file mode 100644 (file)
index 0000000..7258b8e
--- /dev/null
@@ -0,0 +1,51 @@
+-- uuid support function uninstall script
+-- written by nathan wagner and placed in the public domain
+
+drop function uuid_v1();
+drop function uuid_v1mc();
+drop function uuid_v3(uuid, text);
+drop function uuid_v4();
+drop function uuid_v5(uuid, text);
+drop function uuid_recent();
+drop function uuid_nil();
+drop function uuid_ns_dns();
+drop function uuid_ns_oid();
+drop function uuid_ns_url();
+drop function uuid_ns_x500();
+drop function uuid_url(text);
+drop function uuid_dns(text);
+drop function uuid_oid(text);
+drop function uuid_x500(text);
+
+-- Casts
+
+-- Bytea
+
+drop cast if exists (uuid as bytea);
+drop cast if exists (bytea as uuid);
+drop function uuid_bytea_cast(uuid);
+drop function uuid_bytea_uncast(bytea);
+
+-- Numeric
+
+drop cast if exists (uuid as numeric);
+drop cast if exists (numeric as uuid);
+drop function uuid_numeric_cast(uuid);
+drop function uuid_numeric_uncast(numeric);
+
+-- Bit and bit varying
+
+drop cast if exists (uuid as bit(128));
+drop cast if exists (uuid as bit varying);
+drop cast if exists (bit(128) as uuid);
+drop cast if exists (bit varying as uuid);
+
+drop function uuid_bit_cast(uuid);
+drop function uuid_bit_uncast(bit(128));
+
+-- Field extraction functions
+
+drop function uuid_version(uuid);
+drop function uuid_macaddr(uuid);
+drop function uuid_timestamp(uuid);
+drop function uuid_timestamptz(uuid);
diff --git a/postgres/uuid.c b/postgres/uuid.c
new file mode 100644 (file)
index 0000000..eb55399
--- /dev/null
@@ -0,0 +1,437 @@
+/*
+ * uuid type support functions for Postgres 8.4
+ *
+ * written by Nathan Wagner and placed in the public domain
+ */
+#include "postgres.h"
+#include "fmgr.h"
+
+#include "utils/builtins.h"
+#include "utils/uuid.h"
+#include "utils/numeric.h"
+#include "utils/inet.h"
+#include "utils/timestamp.h"
+#include "utils/datetime.h"
+#include "utils/varbit.h"
+
+#include "pduuid.h"
+
+#define UUID_LEN_BIN 16
+
+PG_MODULE_MAGIC;
+
+void _PG_init(void);
+void _PG_fini(void);
+
+Datum uuid_nil(PG_FUNCTION_ARGS);
+Datum uuid_dns(PG_FUNCTION_ARGS);
+Datum uuid_url(PG_FUNCTION_ARGS);
+Datum uuid_oid(PG_FUNCTION_ARGS);
+Datum uuid_x500(PG_FUNCTION_ARGS);
+Datum uuid_recent(PG_FUNCTION_ARGS);
+Datum uuid_gen_v1(PG_FUNCTION_ARGS);
+Datum uuid_gen_v1_mc(PG_FUNCTION_ARGS);
+Datum uuid_gen_v3(PG_FUNCTION_ARGS);
+Datum uuid_gen_v4(PG_FUNCTION_ARGS);
+Datum uuid_gen_v5(PG_FUNCTION_ARGS);
+Datum uuid_cast_bit(PG_FUNCTION_ARGS);
+Datum uuid_cast_from_bit(PG_FUNCTION_ARGS);
+Datum uuid_cast_numeric(PG_FUNCTION_ARGS);
+Datum uuid_cast_from_numeric(PG_FUNCTION_ARGS);
+Datum uuid_cast_bytea(PG_FUNCTION_ARGS);
+Datum uuid_cast_from_bytea(PG_FUNCTION_ARGS);
+Datum uuid_extract_version(PG_FUNCTION_ARGS);
+Datum uuid_extract_macaddr(PG_FUNCTION_ARGS);
+Datum uuid_extract_timestamp(PG_FUNCTION_ARGS);
+
+Datum uuid_ns_dns(PG_FUNCTION_ARGS);
+Datum uuid_ns_url(PG_FUNCTION_ARGS);
+Datum uuid_ns_oid(PG_FUNCTION_ARGS);
+Datum uuid_ns_x500(PG_FUNCTION_ARGS);
+
+static pd_uuid_t       i_gid;
+static pd_uuid_t       i_ns_uuid;
+static pd_uuid_t       *gid = NULL;
+static pd_uuid_t       *ns_uuid = NULL;
+static struct pd_uuid_state    us;
+
+void _PG_init(void) {
+       gid = &i_gid;
+       memset(gid, 0, 16);
+       ns_uuid = &i_ns_uuid;
+       memset(ns_uuid, 0, 16);
+
+       pd_uuid_init_state(&us);
+
+       return;
+}
+
+#if 0
+void _PG_fini(void) {
+       if (gid) {
+               uuid_destroy(gid);
+       }
+       if (ns_uuid) {
+               uuid_destroy(ns_uuid);
+       }
+       return;
+}
+#endif
+
+PG_FUNCTION_INFO_V1(uuid_nil);
+Datum uuid_nil(PG_FUNCTION_ARGS) {
+       pg_uuid_t *uuid;
+
+       uuid = palloc(UUID_LEN_BIN);
+       memset(uuid, 0, 16);
+       PG_RETURN_UUID_P(uuid);
+}
+
+PG_FUNCTION_INFO_V1(uuid_dns);
+Datum uuid_dns(PG_FUNCTION_ARGS) {
+       pg_uuid_t *uuid;
+       unsigned char bytes[] = { 0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11,
+               0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 };
+
+       uuid = palloc(UUID_LEN_BIN);
+       memcpy(uuid, bytes, 16);
+       PG_RETURN_UUID_P(uuid);
+}
+
+PG_FUNCTION_INFO_V1(uuid_url);
+Datum uuid_url(PG_FUNCTION_ARGS) {
+       pg_uuid_t *uuid;
+       unsigned char bytes[] = { 0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11,
+               0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 };
+
+       uuid = palloc(UUID_LEN_BIN);
+       memcpy(uuid, bytes, 16);
+       PG_RETURN_UUID_P(uuid);
+}
+
+PG_FUNCTION_INFO_V1(uuid_oid);
+Datum uuid_oid(PG_FUNCTION_ARGS) {
+       pg_uuid_t *uuid;
+       unsigned char bytes[] = { 0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11,
+               0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 };
+
+       uuid = palloc(UUID_LEN_BIN);
+       memcpy(uuid, bytes, 16);
+       PG_RETURN_UUID_P(uuid);
+}
+
+PG_FUNCTION_INFO_V1(uuid_x500);
+Datum uuid_x500(PG_FUNCTION_ARGS) {
+       pg_uuid_t *uuid;
+       unsigned char bytes[] = { 0x6b, 0xa7, 0xb8, 0x13, 0x9d, 0xad, 0x11,
+               0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 };
+
+       uuid = palloc(UUID_LEN_BIN);
+       memcpy(uuid, bytes, 16);
+       PG_RETURN_UUID_P(uuid);
+}
+
+static pg_uuid_t *export(pd_uuid_t *u) {
+       pg_uuid_t *pgid;
+
+       pgid = palloc(UUID_LEN_BIN);
+       memcpy(pgid, u, 16);
+
+       return pgid;
+}
+
+static void import(pd_uuid_t *u, pg_uuid_t *pgid) {
+       memcpy(u, pgid, 16);
+}
+
+PG_FUNCTION_INFO_V1(uuid_recent);
+
+Datum uuid_recent(PG_FUNCTION_ARGS) {
+       pg_uuid_t *pgid;
+
+       pgid = export(gid);
+       PG_RETURN_UUID_P(pgid);
+}
+
+PG_FUNCTION_INFO_V1(uuid_gen_v1);
+
+Datum uuid_gen_v1(PG_FUNCTION_ARGS) {
+       pg_uuid_t *pgid;
+       
+       if (!pd_uuid_make_v1(&us, gid)) {
+               elog(ERROR, "can't make uuid");
+       }
+
+       pgid = export(gid);
+       PG_RETURN_UUID_P(pgid);
+}
+
+PG_FUNCTION_INFO_V1(uuid_gen_v1_mc);
+
+Datum uuid_gen_v1_mc(PG_FUNCTION_ARGS) {
+       pg_uuid_t *pgid;
+       
+       if (!pd_uuid_make_v1mc(&us, gid)) {
+               elog(ERROR, "can't make uuid");
+       }
+
+       pgid = export(gid);
+       PG_RETURN_UUID_P(pgid);
+}
+
+PG_FUNCTION_INFO_V1(uuid_gen_v3);
+
+Datum uuid_gen_v3(PG_FUNCTION_ARGS) {
+       pg_uuid_t *pgid;
+       pg_uuid_t *ns;
+       text    *t;
+       char *string;
+       
+       ns = PG_GETARG_UUID_P(0);
+       t = PG_GETARG_TEXT_P(1);
+
+       import(ns_uuid, ns);
+
+       string = text_to_cstring(t);
+
+       if (!pd_uuid_make_v3(&us, gid, ns_uuid, string, strlen(string))) {
+               elog(ERROR, "can't make uuid");
+       }
+       pfree(string);
+
+       pgid = export(gid);
+       PG_RETURN_UUID_P(pgid);
+}
+
+PG_FUNCTION_INFO_V1(uuid_gen_v4);
+
+Datum uuid_gen_v4(PG_FUNCTION_ARGS) {
+       pg_uuid_t *pgid;
+
+       if (!pd_uuid_make_v4(&us, gid)) {
+               elog(ERROR, "can't make uuid");
+       }
+
+       pgid = export(gid);
+       PG_RETURN_UUID_P(pgid);
+}
+
+PG_FUNCTION_INFO_V1(uuid_gen_v5);
+
+Datum uuid_gen_v5(PG_FUNCTION_ARGS) {
+       pg_uuid_t *pgid;
+       pg_uuid_t *ns;
+       text    *t;
+       char *string;
+       
+       if (!gid || !ns_uuid) {
+               elog(ERROR, "UUID library failed to initialize");
+       }
+
+       ns = PG_GETARG_UUID_P(0);
+       t = PG_GETARG_TEXT_P(1);
+
+       import(ns_uuid, ns);
+
+       string = text_to_cstring(t);
+
+       if (!pd_uuid_make_v5(&us, gid,ns_uuid, string, strlen(string))) {
+               elog(ERROR, "can't make uuid");
+       }
+       pfree(string);
+
+       pgid = export(gid);
+       PG_RETURN_UUID_P(pgid);
+}
+
+PG_FUNCTION_INFO_V1(uuid_cast_bit);
+Datum uuid_cast_bit(PG_FUNCTION_ARGS) {
+       VarBit  *bit;
+
+       pg_uuid_t *uuid = PG_GETARG_UUID_P(0);
+
+       bit = palloc(VARBITTOTALLEN(128));
+       bit->bit_len = 128;
+       bit->vl_len_ = VARBITTOTALLEN(128);
+       memcpy(VARBITS(bit), uuid, 16);
+       PG_RETURN_VARBIT_P(bit);
+}
+
+PG_FUNCTION_INFO_V1(uuid_cast_from_bit);
+Datum uuid_cast_from_bit(PG_FUNCTION_ARGS) {
+       pg_uuid_t *uuid;
+
+       VarBit  *bit = PG_GETARG_VARBIT_P(0);
+
+       if (bit->bit_len != 128) {
+               /* Throw error? */
+               elog(ERROR, "can't cast from bit(%d) to uuid, must cast from bit(128)", bit->bit_len);
+       }
+
+       uuid = palloc(UUID_LEN_BIN);
+       memcpy(uuid, VARBITS(bit), 16);
+       PG_RETURN_UUID_P(uuid);
+}
+
+PG_FUNCTION_INFO_V1(uuid_cast_bytea);
+Datum uuid_cast_bytea(PG_FUNCTION_ARGS) {
+       bytea   *bit;
+
+       pg_uuid_t *uuid = PG_GETARG_UUID_P(0);
+
+       bit = palloc(VARHDRSZ + 16);
+       SET_VARSIZE(bit, VARHDRSZ + 16);
+       memcpy(VARDATA(bit), uuid, 16);
+       PG_RETURN_BYTEA_P(bit);
+}
+
+PG_FUNCTION_INFO_V1(uuid_cast_from_bytea);
+Datum uuid_cast_from_bytea(PG_FUNCTION_ARGS) {
+       pg_uuid_t *uuid; 
+
+       bytea   *bit = PG_GETARG_BYTEA_P(0);
+
+       if (VARSIZE_ANY_EXHDR(bit) != 16) {
+               elog(ERROR, "invalid length of bytea for cast to uuid, need 16, attempted %d", VARSIZE_ANY_EXHDR(bit));
+       }
+
+       uuid = palloc(UUID_LEN_BIN);
+       memcpy(uuid, VARDATA(bit), 16);
+       PG_RETURN_UUID_P(uuid);
+}
+
+/* TODO construct the uuid directly from the numeric */
+/* TODO have a static c256 numeric */
+
+PG_FUNCTION_INFO_V1(uuid_cast_from_numeric);
+Datum uuid_cast_from_numeric(PG_FUNCTION_ARGS) {
+       int i;
+       unsigned char *data;
+       int32   byte;
+
+       Numeric c256;
+       Numeric input;
+       Numeric result;
+       pg_uuid_t       *uuid;
+
+       input = PG_GETARG_NUMERIC(0);
+       uuid = palloc(UUID_LEN_BIN);
+       data = (unsigned char *)uuid;
+
+       c256 = DatumGetNumeric(DirectFunctionCall1(int4_numeric, Int32GetDatum(256)));
+
+       for (i=15;i>=0;i--) {
+               result = DatumGetNumeric(DirectFunctionCall2(numeric_mod, NumericGetDatum(input), NumericGetDatum(c256)));
+
+               input = DatumGetNumeric(DirectFunctionCall2(numeric_div_trunc, NumericGetDatum(input), NumericGetDatum(c256)));
+
+               byte = DatumGetInt32(DirectFunctionCall1(numeric_int4, NumericGetDatum(result)));
+               data[i] = byte & 0xff;
+       }
+
+       /* TODO will this leak if I don't do this?  Segfault if i do? */
+       pfree(c256);
+
+       PG_RETURN_UUID_P(uuid);
+}
+
+/*
+ * TODO construct the numeric directly
+ */
+PG_FUNCTION_INFO_V1(uuid_cast_numeric);
+Datum uuid_cast_numeric(PG_FUNCTION_ARGS) {
+       int i;
+       unsigned char *data;
+       int32   byte;
+
+       Numeric result;
+       Numeric c256;
+
+       pg_uuid_t *uuid = PG_GETARG_UUID_P(0);
+
+       data = (unsigned char *)uuid;
+
+       result = DatumGetNumeric(DirectFunctionCall1(int4_numeric, Int32GetDatum(0)));
+       
+       c256 = DatumGetNumeric(DirectFunctionCall1(int4_numeric, Int32GetDatum(256)));
+
+       for (i=0;i<16;i++) {
+               byte = (int32) data[i];
+
+               result = DatumGetNumeric(DirectFunctionCall2(numeric_mul, NumericGetDatum(result), NumericGetDatum(c256)));
+
+               result = DatumGetNumeric(
+                               DirectFunctionCall2(numeric_add,
+                                       NumericGetDatum(result),
+                                       DirectFunctionCall1(int4_numeric, Int32GetDatum(byte))));
+
+       }
+
+       pfree(c256);
+
+       PG_RETURN_NUMERIC(result);
+}
+
+PG_FUNCTION_INFO_V1(uuid_extract_version);
+Datum uuid_extract_version(PG_FUNCTION_ARGS) {
+       int32 version;
+       unsigned char *data;
+
+       pg_uuid_t *uuid = PG_GETARG_UUID_P(0);
+       data = (unsigned char *)uuid;
+
+       version = data[6] >> 4;
+       PG_RETURN_INT32(version);
+}
+
+PG_FUNCTION_INFO_V1(uuid_extract_macaddr);
+Datum uuid_extract_macaddr(PG_FUNCTION_ARGS) {
+       macaddr *mac;
+       unsigned char *data;
+
+       pg_uuid_t *uuid = PG_GETARG_UUID_P(0);
+       data = (unsigned char *)uuid;
+
+       mac = palloc(sizeof *mac);
+       mac->a = data[10];
+       mac->b = data[11];
+       mac->c = data[12];
+       mac->d = data[13];
+       mac->e = data[14];
+       mac->f = data[15];
+
+       PG_RETURN_MACADDR_P(mac);
+}
+
+/* number of 100 nanosecond intervals from 1585-10-15 to 1970-01-01 */
+#define GREGORIAN 122192928000000000ULL
+
+PG_FUNCTION_INFO_V1(uuid_extract_timestamp);
+Datum uuid_extract_timestamp(PG_FUNCTION_ARGS) {
+       Timestamp ts;
+       unsigned char *data;
+
+       pg_uuid_t *uuid = PG_GETARG_UUID_P(0);
+       data = (unsigned char *)uuid;
+
+       ts = (data[6] & 0xf);
+       ts *= 256; ts += (data[7] & 0xff);
+       ts *= 256; ts += (data[4] & 0xff);
+       ts *= 256; ts += (data[5] & 0xff);
+       ts *= 256; ts += (data[0] & 0xff);
+       ts *= 256; ts += (data[1] & 0xff);
+       ts *= 256; ts += (data[2] & 0xff);
+       ts *= 256; ts += (data[3] & 0xff);
+
+       /* TODO could probably combine some of this */
+       ts -= GREGORIAN; /* adjust by offset from gregorian to unix epoch */
+       ts /= 10; /* convert from 100 ns to us */
+
+       ts -= ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY * 1000000LL);
+
+#ifdef HAVE_INT64_TIMESTAMP
+       PG_RETURN_TIMESTAMP(ts);
+#else
+       PG_RETURN_TIMESTAMP(ts/1000000UL);
+#endif
+}
diff --git a/rng.c b/rng.c
new file mode 100644 (file)
index 0000000..89eed89
--- /dev/null
+++ b/rng.c
@@ -0,0 +1,139 @@
+/*
+ * Adaped from libtomcrypt by Tom St Denis.
+ *
+ * by Nathan Wagner, and released into the public domain
+ */
+
+#include <stdio.h>
+
+#define LTC_ARGCHK(x)
+#define TRY_URANDOM_FIRST 1
+
+#ifndef WIN32
+#define LTC_DEVRANDOM 1
+#endif
+
+#ifdef LTC_DEVRANDOM
+/* on *NIX read /dev/random */
+static unsigned long rng_nix(unsigned char *buf, unsigned long len) {
+#ifdef LTC_NO_FILE
+       return 0;
+#else
+       FILE           *f;
+       unsigned long   x;
+#ifdef TRY_URANDOM_FIRST
+       f = fopen("/dev/urandom", "rb");
+       if (f == NULL)
+#endif
+               f = fopen("/dev/random", "rb");
+
+       if (f == NULL) {
+               return 0;
+       }
+       /* disable buffering */
+       if (setvbuf(f, NULL, _IONBF, 0) != 0) {
+               fclose(f);
+               return 0;
+       }
+       x = (unsigned long) fread(buf, 1, (size_t) len, f);
+       fclose(f);
+       return x;
+#endif
+}
+
+#endif
+
+/* TODO remove this.  It's too slow really (I think) */
+/* on ANSI C platforms with 100 < CLOCKS_PER_SEC < 10000 */
+#if defined(CLOCKS_PER_SEC) && !defined(WINCE)
+
+#define ANSI_RNG
+
+static unsigned long rng_ansic(unsigned char *buf, unsigned long len) {
+       clock_t         t1;
+       int             l, acc, bits, a, b;
+
+       if (XCLOCKS_PER_SEC < 100 || XCLOCKS_PER_SEC > 10000) {
+               return 0;
+       }
+       l = len;
+       bits = 8;
+       acc = a = b = 0;
+       while (len--) {
+               while (bits--) {
+                       do {
+                               t1 = XCLOCK();
+                               while (t1 == XCLOCK())
+                                       a ^= 1;
+                               t1 = XCLOCK();
+                               while (t1 == XCLOCK())
+                                       b ^= 1;
+                       } while (a == b);
+                       acc = (acc << 1) | a;
+               }
+               *buf++ = acc;
+               acc = 0;
+               bits = 8;
+       }
+       acc = bits = a = b = 0;
+       return l;
+}
+
+#endif
+
+/* Try the Microsoft CSP */
+#if defined(WIN32) || defined(WINCE)
+#warning using WIN32
+#define _WIN32_WINNT 0x0400
+#ifdef WINCE
+#define UNDER_CE
+#define ARM
+#endif
+#include <windows.h>
+#include <wincrypt.h>
+
+static unsigned long rng_win32(unsigned char *buf, unsigned long len) {
+       HCRYPTPROV      hProv = 0;
+
+       if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL,
+                           (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)) &&
+           !CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL,
+             CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET))
+               return 0;
+
+       if (CryptGenRandom(hProv, len, buf) == TRUE) {
+               CryptReleaseContext(hProv, 0);
+               return len;
+       } else {
+               CryptReleaseContext(hProv, 0);
+               return 0;
+       }
+}
+
+#endif
+
+unsigned long   pd_uuid_rng_get_bytes(unsigned char *out, unsigned long outlen) {
+       unsigned long   x;
+
+       LTC_ARGCHK(out != NULL);
+
+#if defined(LTC_DEVRANDOM)
+       x = rng_nix(out, outlen);
+       if (x != 0) {
+               return x;
+       }
+#endif
+#ifdef WIN32
+       x = rng_win32(out, outlen);
+       if (x != 0) {
+               return x;
+       }
+#endif
+#ifdef ANSI_RNG
+       x = rng_ansic(out, outlen);
+       if (x != 0) {
+               return x;
+       }
+#endif
+       return 0;
+}
diff --git a/sha1.c b/sha1.c
new file mode 100644 (file)
index 0000000..0e45979
--- /dev/null
+++ b/sha1.c
@@ -0,0 +1,216 @@
+/*
+ * Adapted from libtomcrypt by Tom St Denis
+ *
+ * by Nathan Wagner and released into the public domain
+ */
+
+#define ENDIAN_NEUTRAL 1
+#define LTC_SMALL_CODE 1
+
+#include "tomcrypt_macros.h"
+#include "hash.h"
+
+#define F0(x,y,z)  (z ^ (x & (y ^ z)))
+#define F1(x,y,z)  (x ^ y ^ z)
+#define F2(x,y,z)  ((x & y) | (z & (x | y)))
+#define F3(x,y,z)  (x ^ y ^ z)
+
+static int  sha1_compress(hash_state *md, unsigned char *buf)
+{
+    ulong32 a,b,c,d,e,W[80],i;
+#ifdef LTC_SMALL_CODE
+    ulong32 t;
+#endif
+
+    /* copy the state into 512-bits into W[0..15] */
+    for (i = 0; i < 16; i++) {
+        LOAD32H(W[i], buf + (4*i));
+    }
+
+    /* copy state */
+    a = md->sha1.state[0];
+    b = md->sha1.state[1];
+    c = md->sha1.state[2];
+    d = md->sha1.state[3];
+    e = md->sha1.state[4];
+
+    /* expand it */
+    for (i = 16; i < 80; i++) {
+        W[i] = ROL(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1); 
+    }
+
+    /* compress */
+    /* round one */
+    #define FF0(a,b,c,d,e,i) e = (ROL(a, 5) + F0(b,c,d) + e + W[i] + 0x5a827999UL); b = ROL(b, 30);
+    #define FF1(a,b,c,d,e,i) e = (ROL(a, 5) + F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); b = ROL(b, 30);
+    #define FF2(a,b,c,d,e,i) e = (ROL(a, 5) + F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); b = ROL(b, 30);
+    #define FF3(a,b,c,d,e,i) e = (ROL(a, 5) + F3(b,c,d) + e + W[i] + 0xca62c1d6UL); b = ROL(b, 30);
+#ifdef LTC_SMALL_CODE
+    for (i = 0; i < 20; ) {
+       FF0(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
+    }
+
+    for (; i < 40; ) {
+       FF1(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
+    }
+
+    for (; i < 60; ) {
+       FF2(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
+    }
+
+    for (; i < 80; ) {
+       FF3(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
+    }
+
+#else
+
+    for (i = 0; i < 20; ) {
+       FF0(a,b,c,d,e,i++);
+       FF0(e,a,b,c,d,i++);
+       FF0(d,e,a,b,c,i++);
+       FF0(c,d,e,a,b,i++);
+       FF0(b,c,d,e,a,i++);
+    }
+
+    /* round two */
+    for (; i < 40; )  { 
+       FF1(a,b,c,d,e,i++);
+       FF1(e,a,b,c,d,i++);
+       FF1(d,e,a,b,c,i++);
+       FF1(c,d,e,a,b,i++);
+       FF1(b,c,d,e,a,i++);
+    }
+
+    /* round three */
+    for (; i < 60; )  { 
+       FF2(a,b,c,d,e,i++);
+       FF2(e,a,b,c,d,i++);
+       FF2(d,e,a,b,c,i++);
+       FF2(c,d,e,a,b,i++);
+       FF2(b,c,d,e,a,i++);
+    }
+
+    /* round four */
+    for (; i < 80; )  { 
+       FF3(a,b,c,d,e,i++);
+       FF3(e,a,b,c,d,i++);
+       FF3(d,e,a,b,c,i++);
+       FF3(c,d,e,a,b,i++);
+       FF3(b,c,d,e,a,i++);
+    }
+#endif
+
+    #undef FF0
+    #undef FF1
+    #undef FF2
+    #undef FF3
+
+    /* store */
+    md->sha1.state[0] = md->sha1.state[0] + a;
+    md->sha1.state[1] = md->sha1.state[1] + b;
+    md->sha1.state[2] = md->sha1.state[2] + c;
+    md->sha1.state[3] = md->sha1.state[3] + d;
+    md->sha1.state[4] = md->sha1.state[4] + e;
+
+    return CRYPT_OK;
+}
+
+int sha1_init(hash_state * md)
+{
+   LTC_ARGCHK(md != NULL);
+   md->sha1.state[0] = 0x67452301UL;
+   md->sha1.state[1] = 0xefcdab89UL;
+   md->sha1.state[2] = 0x98badcfeUL;
+   md->sha1.state[3] = 0x10325476UL;
+   md->sha1.state[4] = 0xc3d2e1f0UL;
+   md->sha1.curlen = 0;
+   md->sha1.length = 0;
+   return CRYPT_OK;
+}
+
+HASH_PROCESS(sha1_process, sha1_compress, sha1, 64)
+
+int sha1_done(hash_state * md, unsigned char *out) {
+    int i;
+
+    LTC_ARGCHK(md  != NULL);
+    LTC_ARGCHK(out != NULL);
+
+    if (md->sha1.curlen >= sizeof(md->sha1.buf)) {
+       return CRYPT_INVALID_ARG;
+    }
+
+    /* increase the length of the message */
+    md->sha1.length += md->sha1.curlen * 8;
+
+    /* append the '1' bit */
+    md->sha1.buf[md->sha1.curlen++] = (unsigned char)0x80;
+
+    /* if the length is currently above 56 bytes we append zeros
+     * then compress.  Then we can fall back to padding zeros and length
+     * encoding like normal.
+     */
+    if (md->sha1.curlen > 56) {
+        while (md->sha1.curlen < 64) {
+            md->sha1.buf[md->sha1.curlen++] = (unsigned char)0;
+        }
+        sha1_compress(md, md->sha1.buf);
+        md->sha1.curlen = 0;
+    }
+
+    /* pad upto 56 bytes of zeroes */
+    while (md->sha1.curlen < 56) {
+        md->sha1.buf[md->sha1.curlen++] = (unsigned char)0;
+    }
+
+    /* store length */
+    STORE64H(md->sha1.length, md->sha1.buf+56);
+    sha1_compress(md, md->sha1.buf);
+
+    /* copy output */
+    for (i = 0; i < 5; i++) {
+        STORE32H(md->sha1.state[i], out+(4*i));
+    }
+#ifdef LTC_CLEAN_STACK
+    zeromem(md, sizeof(hash_state));
+#endif
+    return CRYPT_OK;
+}
+
+int  sha1_test(void) {
+ #if 0
+    return CRYPT_NOP;
+ #else    
+  static const struct {
+      char *msg;
+      unsigned char hash[20];
+  } tests[] = {
+    { "abc",
+      { 0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a,
+        0xba, 0x3e, 0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c,
+        0x9c, 0xd0, 0xd8, 0x9d }
+    },
+    { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+      { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E,
+        0xBA, 0xAE, 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5,
+        0xE5, 0x46, 0x70, 0xF1 }
+    }
+  };
+
+  int i;
+  unsigned char tmp[20];
+  hash_state md;
+
+  for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0]));  i++) {
+      sha1_init(&md);
+      sha1_process(&md, (unsigned char*)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+      sha1_done(&md, tmp);
+      if (XMEMCMP(tmp, tests[i].hash, 20) != 0) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+  }
+  return CRYPT_OK;
+  #endif
+}
diff --git a/tomcrypt_macros.h b/tomcrypt_macros.h
new file mode 100644 (file)
index 0000000..8eb4b42
--- /dev/null
@@ -0,0 +1,426 @@
+/* fix for MSVC ...evil! */
+#if 0
+#ifdef _MSC_VER
+   #define CONST64(n) n ## ui64
+   typedef unsigned __int64 ulong64;
+#else
+   #define CONST64(n) n ## ULL
+   typedef unsigned long long ulong64;
+#endif
+
+/* this is the "32-bit at least" data type 
+ * Re-define it to suit your platform but it must be at least 32-bits 
+ */
+#if defined(__x86_64__) || (defined(__sparc__) && defined(__arch64__))
+   typedef unsigned ulong32;
+#else
+   typedef unsigned long ulong32;
+#endif
+#endif
+
+/* ---- HELPER MACROS ---- */
+#ifdef ENDIAN_NEUTRAL
+
+#define STORE32L(x, y)                                                                     \
+     { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255);   \
+       (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD32L(x, y)                            \
+     { x = ((unsigned long)((y)[3] & 255)<<24) | \
+           ((unsigned long)((y)[2] & 255)<<16) | \
+           ((unsigned long)((y)[1] & 255)<<8)  | \
+           ((unsigned long)((y)[0] & 255)); }
+
+#define STORE64L(x, y)                                                                     \
+     { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255);   \
+       (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255);   \
+       (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255);   \
+       (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD64L(x, y)                                                       \
+     { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \
+           (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \
+           (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \
+           (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
+
+#define STORE32H(x, y)                                                                     \
+     { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255);   \
+       (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
+
+#define LOAD32H(x, y)                            \
+     { x = ((unsigned long)((y)[0] & 255)<<24) | \
+           ((unsigned long)((y)[1] & 255)<<16) | \
+           ((unsigned long)((y)[2] & 255)<<8)  | \
+           ((unsigned long)((y)[3] & 255)); }
+
+#define STORE64H(x, y)                                                                     \
+   { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255);     \
+     (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255);     \
+     (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255);     \
+     (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+
+#define LOAD64H(x, y)                                                      \
+   { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \
+         (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \
+         (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \
+         (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); }
+
+#endif /* ENDIAN_NEUTRAL */
+
+#ifdef ENDIAN_LITTLE
+
+#if !defined(LTC_NO_BSWAP) && (defined(INTEL_CC) || (defined(__GNUC__) && (defined(__DJGPP__) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__i386__) || defined(__x86_64__))))
+
+#define STORE32H(x, y)           \
+asm __volatile__ (               \
+   "bswapl %0     \n\t"          \
+   "movl   %0,(%1)\n\t"          \
+   "bswapl %0     \n\t"          \
+      ::"r"(x), "r"(y));
+
+#define LOAD32H(x, y)          \
+asm __volatile__ (             \
+   "movl (%1),%0\n\t"          \
+   "bswapl %0\n\t"             \
+   :"=r"(x): "r"(y));
+
+#else
+
+#define STORE32H(x, y)                                                                     \
+     { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255);   \
+       (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
+
+#define LOAD32H(x, y)                            \
+     { x = ((unsigned long)((y)[0] & 255)<<24) | \
+           ((unsigned long)((y)[1] & 255)<<16) | \
+           ((unsigned long)((y)[2] & 255)<<8)  | \
+           ((unsigned long)((y)[3] & 255)); }
+
+#endif
+
+
+/* x86_64 processor */
+#if !defined(LTC_NO_BSWAP) && (defined(__GNUC__) && defined(__x86_64__))
+
+#define STORE64H(x, y)           \
+asm __volatile__ (               \
+   "bswapq %0     \n\t"          \
+   "movq   %0,(%1)\n\t"          \
+   "bswapq %0     \n\t"          \
+      ::"r"(x), "r"(y));
+
+#define LOAD64H(x, y)          \
+asm __volatile__ (             \
+   "movq (%1),%0\n\t"          \
+   "bswapq %0\n\t"             \
+   :"=r"(x): "r"(y));
+
+#else
+
+#define STORE64H(x, y)                                                                     \
+   { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255);     \
+     (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255);     \
+     (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255);     \
+     (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+
+#define LOAD64H(x, y)                                                      \
+   { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \
+         (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \
+         (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \
+         (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); }
+
+#endif
+
+#ifdef ENDIAN_32BITWORD 
+
+#define STORE32L(x, y)        \
+     { ulong32  __t = (x); XMEMCPY(y, &__t, 4); }
+
+#define LOAD32L(x, y)         \
+     XMEMCPY(&(x), y, 4);
+
+#define STORE64L(x, y)                                                                     \
+     { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255);   \
+       (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255);   \
+       (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255);   \
+       (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD64L(x, y)                                                       \
+     { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \
+           (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \
+           (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \
+           (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
+
+#else /* 64-bit words then  */
+
+#define STORE32L(x, y)        \
+     { ulong32 __t = (x); XMEMCPY(y, &__t, 4); }
+
+#define LOAD32L(x, y)         \
+     { XMEMCPY(&(x), y, 4); x &= 0xFFFFFFFF; }
+
+#define STORE64L(x, y)        \
+     { ulong64 __t = (x); XMEMCPY(y, &__t, 8); }
+
+#define LOAD64L(x, y)         \
+    { XMEMCPY(&(x), y, 8); }
+
+#endif /* ENDIAN_64BITWORD */
+
+#endif /* ENDIAN_LITTLE */
+
+#ifdef ENDIAN_BIG
+#define STORE32L(x, y)                                                                     \
+     { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255);   \
+       (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD32L(x, y)                            \
+     { x = ((unsigned long)((y)[3] & 255)<<24) | \
+           ((unsigned long)((y)[2] & 255)<<16) | \
+           ((unsigned long)((y)[1] & 255)<<8)  | \
+           ((unsigned long)((y)[0] & 255)); }
+
+#define STORE64L(x, y)                                                                     \
+   { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255);     \
+     (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255);     \
+     (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255);     \
+     (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD64L(x, y)                                                      \
+   { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48) | \
+         (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32) | \
+         (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16) | \
+         (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
+
+#ifdef ENDIAN_32BITWORD 
+
+#define STORE32H(x, y)        \
+     { ulong32 __t = (x); XMEMCPY(y, &__t, 4); }
+
+#define LOAD32H(x, y)         \
+     XMEMCPY(&(x), y, 4);
+
+#define STORE64H(x, y)                                                                     \
+     { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255);   \
+       (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255);   \
+       (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255);   \
+       (y)[6] = (unsigned char)(((x)>>8)&255);  (y)[7] = (unsigned char)((x)&255); }
+
+#define LOAD64H(x, y)                                                       \
+     { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48)| \
+           (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32)| \
+           (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16)| \
+           (((ulong64)((y)[6] & 255))<<8)| (((ulong64)((y)[7] & 255))); }
+
+#else /* 64-bit words then  */
+
+#define STORE32H(x, y)        \
+     { ulong32 __t = (x); XMEMCPY(y, &__t, 4); }
+
+#define LOAD32H(x, y)         \
+     { XMEMCPY(&(x), y, 4); x &= 0xFFFFFFFF; }
+
+#define STORE64H(x, y)        \
+     { ulong64 __t = (x); XMEMCPY(y, &__t, 8); }
+
+#define LOAD64H(x, y)         \
+    { XMEMCPY(&(x), y, 8); }
+
+#endif /* ENDIAN_64BITWORD */
+#endif /* ENDIAN_BIG */
+
+#define BSWAP(x)  ( ((x>>24)&0x000000FFUL) | ((x<<24)&0xFF000000UL)  | \
+                    ((x>>8)&0x0000FF00UL)  | ((x<<8)&0x00FF0000UL) )
+
+
+/* 32-bit Rotates */
+#if defined(_MSC_VER)
+
+/* instrinsic rotate */
+#include <stdlib.h>
+#pragma intrinsic(_lrotr,_lrotl)
+#define ROR(x,n) _lrotr(x,n)
+#define ROL(x,n) _lrotl(x,n)
+#define RORc(x,n) _lrotr(x,n)
+#define ROLc(x,n) _lrotl(x,n)
+
+#elif !defined(__STRICT_ANSI__) && defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && !defined(INTEL_CC) && !defined(LTC_NO_ASM)
+
+static inline unsigned ROL(unsigned word, int i)
+{
+   asm ("roll %%cl,%0"
+      :"=r" (word)
+      :"0" (word),"c" (i));
+   return word;
+}
+
+static inline unsigned ROR(unsigned word, int i)
+{
+   asm ("rorl %%cl,%0"
+      :"=r" (word)
+      :"0" (word),"c" (i));
+   return word;
+}
+
+#ifndef LTC_NO_ROLC
+
+static inline unsigned ROLc(unsigned word, const int i)
+{
+   asm ("roll %2,%0"
+      :"=r" (word)
+      :"0" (word),"I" (i));
+   return word;
+}
+
+static inline unsigned RORc(unsigned word, const int i)
+{
+   asm ("rorl %2,%0"
+      :"=r" (word)
+      :"0" (word),"I" (i));
+   return word;
+}
+
+#else
+
+#define ROLc ROL
+#define RORc ROR
+
+#endif
+
+#elif !defined(__STRICT_ANSI__) && defined(LTC_PPC32)
+
+static inline unsigned ROL(unsigned word, int i)
+{
+   asm ("rotlw %0,%0,%2"
+      :"=r" (word)
+      :"0" (word),"r" (i));
+   return word;
+}
+
+static inline unsigned ROR(unsigned word, int i)
+{
+   asm ("rotlw %0,%0,%2"
+      :"=r" (word)
+      :"0" (word),"r" (32-i));
+   return word;
+}
+
+#ifndef LTC_NO_ROLC
+
+static inline unsigned ROLc(unsigned word, const int i)
+{
+   asm ("rotlwi %0,%0,%2"
+      :"=r" (word)
+      :"0" (word),"I" (i));
+   return word;
+}
+
+static inline unsigned RORc(unsigned word, const int i)
+{
+   asm ("rotrwi %0,%0,%2"
+      :"=r" (word)
+      :"0" (word),"I" (i));
+   return word;
+}
+
+#else
+
+#define ROLc ROL
+#define RORc ROR
+
+#endif
+
+
+#else
+
+/* rotates the hard way */
+#define ROL(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+#define ROR(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+#define ROLc(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+#define RORc(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+
+#endif
+
+
+/* 64-bit Rotates */
+#if !defined(__STRICT_ANSI__) && defined(__GNUC__) && defined(__x86_64__) && !defined(LTC_NO_ASM)
+
+static inline unsigned long ROL64(unsigned long word, int i)
+{
+   asm("rolq %%cl,%0"
+      :"=r" (word)
+      :"0" (word),"c" (i));
+   return word;
+}
+
+static inline unsigned long ROR64(unsigned long word, int i)
+{
+   asm("rorq %%cl,%0"
+      :"=r" (word)
+      :"0" (word),"c" (i));
+   return word;
+}
+
+#ifndef LTC_NO_ROLC
+
+static inline unsigned long ROL64c(unsigned long word, const int i)
+{
+   asm("rolq %2,%0"
+      :"=r" (word)
+      :"0" (word),"J" (i));
+   return word;
+}
+
+static inline unsigned long ROR64c(unsigned long word, const int i)
+{
+   asm("rorq %2,%0"
+      :"=r" (word)
+      :"0" (word),"J" (i));
+   return word;
+}
+
+#else /* LTC_NO_ROLC */
+
+#define ROL64c ROL64
+#define ROR64c ROR64
+
+#endif
+
+#else /* Not x86_64  */
+
+#define ROL64(x, y) \
+    ( (((x)<<((ulong64)(y)&63)) | \
+      (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)64-((y)&63)))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#define ROR64(x, y) \
+    ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \
+      ((x)<<((ulong64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#define ROL64c(x, y) \
+    ( (((x)<<((ulong64)(y)&63)) | \
+      (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)64-((y)&63)))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#define ROR64c(x, y) \
+    ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \
+      ((x)<<((ulong64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#endif
+
+#ifndef MAX
+   #define MAX(x, y) ( ((x)>(y))?(x):(y) )
+#endif
+
+#ifndef MIN
+   #define MIN(x, y) ( ((x)<(y))?(x):(y) )
+#endif
+
+/* extract a byte portably */
+#ifdef _MSC_VER
+   #define byte(x, n) ((unsigned char)((x) >> (8 * (n))))
+#else
+   #define byte(x, n) (((x) >> (8 * (n))) & 255)
+#endif   
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_macros.h,v $ */
+/* $Revision: 1.15 $ */
+/* $Date: 2006/11/29 23:43:57 $ */
diff --git a/uuidgen.c b/uuidgen.c
new file mode 100644 (file)
index 0000000..ada26d0
--- /dev/null
+++ b/uuidgen.c
@@ -0,0 +1,67 @@
+/*
+ * test program for uuid library
+ *
+ * written by nathan wagner and placed in the public domain
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "pduuid.h"
+
+void ufmt(pd_uuid_t *uuid, char *s) {
+       int i;
+       for (i=0;i<4;i++) {
+               s += sprintf(s, "%02x", uuid->data[i]);
+       }
+       s += sprintf(s, "-");
+       for (;i<6;i++) {
+               s += sprintf(s, "%02x", uuid->data[i]);
+       }
+       s += sprintf(s, "-");
+       for (;i<8;i++) {
+               s += sprintf(s, "%02x", uuid->data[i]);
+       }
+       s += sprintf(s, "-");
+       for (;i<10;i++) {
+               s += sprintf(s, "%02x", uuid->data[i]);
+       }
+       s += sprintf(s, "-");
+       for (;i<16;i++) {
+               s += sprintf(s, "%02x", uuid->data[i]);
+       }
+}
+
+int main(int ac, char *av[]) {
+       pd_uuid_t uuid;
+       pd_uuid_t dns;
+       char fmt[37];
+
+#ifdef WIN32
+       srand(time(0));
+#else
+       srandom(time(0));
+#endif
+
+       pd_uuid_make_v1(0, &uuid);
+       ufmt(&uuid, fmt);
+       printf("v1: %s\n", fmt);
+
+       pd_uuid_make_v4(0, &uuid);
+       ufmt(&uuid, fmt);
+       printf("v4: %s\n", fmt);
+
+       pd_uuid_set_string(&dns, "6ba7b810-9dad-11d1-80b4-00c04fd430c8");
+       ufmt(&dns, fmt);
+       printf("dns: %s\n", fmt);
+
+       pd_uuid_make_v3(0, &uuid, &dns, "granicus.if.org", strlen("granicus.if.org"));
+       ufmt(&uuid, fmt);
+       printf("granicus.if.org (v3): %s\n", fmt);
+
+       pd_uuid_make_v5(0, &uuid, &dns, "granicus.if.org", strlen("granicus.if.org"));
+       ufmt(&uuid, fmt);
+       printf("granicus.if.org (v5): %s\n", fmt);
+
+       return 0;
+}