ext/ezmlm/hash/hash.c
changeset 16 e135ccae6783
child 17 23c7f5c8ee39
equal deleted inserted replaced
15:a38e6916504c 16:e135ccae6783
       
     1 
       
     2 #include "hash.h"
       
     3 
       
     4 /*
       
     5  * I originally attemped to just convert surf.c to pure Ruby, but I
       
     6  * confess a lack of understanding surrounding the char casts from
       
     7  * unsigned ints, etc, and screwing up a hash algo doesn't do anyone
       
     8  * any good, least of all, me.  In other words, I don't have to fully
       
     9  * understand DJB code to trust in it. :-)
       
    10  *
       
    11  * The following is copied verbatim from the ezmlm-idx source, version
       
    12  * 7.2.2.  See: subhash.c, surf.c, and surfpcs.c.
       
    13  *
       
    14 */
       
    15 
       
    16 void surf(unsigned int out[8],const unsigned int in[12],const unsigned int seed[32])
       
    17 {
       
    18   unsigned int t[12]; unsigned int x; unsigned int sum = 0;
       
    19   int r; int i; int loop;
       
    20 
       
    21   for (i = 0;i < 12;++i) t[i] = in[i] ^ seed[12 + i];
       
    22   for (i = 0;i < 8;++i) out[i] = seed[24 + i];
       
    23   x = t[11];
       
    24   for (loop = 0;loop < 2;++loop) {
       
    25     for (r = 0;r < 16;++r) {
       
    26       sum += 0x9e3779b9;
       
    27       MUSH(0,5) MUSH(1,7) MUSH(2,9) MUSH(3,13)
       
    28       MUSH(4,5) MUSH(5,7) MUSH(6,9) MUSH(7,13)
       
    29       MUSH(8,5) MUSH(9,7) MUSH(10,9) MUSH(11,13)
       
    30     }
       
    31     for (i = 0;i < 8;++i) out[i] ^= t[i + 4];
       
    32   }
       
    33 }
       
    34 
       
    35 void surfpcs_init(surfpcs *s,const unsigned int k[32])
       
    36 {
       
    37   int i;
       
    38   for (i = 0;i < 32;++i) s->seed[i] = k[i];
       
    39   for (i = 0;i < 8;++i) s->sum[i] = 0;
       
    40   for (i = 0;i < 12;++i) s->in[i] = 0;
       
    41   s->todo = 0;
       
    42 }
       
    43 
       
    44 void surfpcs_add(surfpcs *s,const char *x,unsigned int n)
       
    45 {
       
    46   int i;
       
    47   while (n--) {
       
    48     data[end[s->todo++]] = *x++;
       
    49     if (s->todo == 32) {
       
    50       s->todo = 0;
       
    51       if (!++s->in[8])
       
    52         if (!++s->in[9])
       
    53           if (!++s->in[10])
       
    54             ++s->in[11];
       
    55       surf(s->out,s->in,s->seed);
       
    56       for (i = 0;i < 8;++i)
       
    57 	s->sum[i] += s->out[i];
       
    58     }
       
    59   }
       
    60 }
       
    61 
       
    62 void surfpcs_addlc(surfpcs *s,const char *x,unsigned int n)
       
    63 /* modified from surfpcs_add by case-independence and skipping ' ' & '\t' */
       
    64 {
       
    65   unsigned char ch;
       
    66   int i;
       
    67   while (n--) {
       
    68     ch = *x++;
       
    69     if (ch == ' ' || ch == '\t') continue;
       
    70     if (ch >= 'A' && ch <= 'Z')
       
    71       ch -= 'a' - 'A';
       
    72 
       
    73     data[end[s->todo++]] = ch;
       
    74     if (s->todo == 32) {
       
    75       s->todo = 0;
       
    76       if (!++s->in[8])
       
    77         if (!++s->in[9])
       
    78           if (!++s->in[10])
       
    79             ++s->in[11];
       
    80       surf(s->out,s->in,s->seed);
       
    81       for (i = 0;i < 8;++i)
       
    82 	  s->sum[i] += s->out[i];
       
    83     }
       
    84   }
       
    85 }
       
    86 
       
    87 void surfpcs_out(surfpcs *s,unsigned char h[32])
       
    88 {
       
    89   int i;
       
    90   surfpcs_add(s,".",1);
       
    91   while (s->todo) surfpcs_add(s,"",1);
       
    92   for (i = 0;i < 8;++i) s->in[i] = s->sum[i];
       
    93   for (;i < 12;++i) s->in[i] = 0;
       
    94   surf(s->out,s->in,s->seed);
       
    95   for (i = 0;i < 32;++i) h[i] = outdata[end[i]];
       
    96 }
       
    97 
       
    98 void makehash(const char *indata,unsigned int inlen,char *hash)
       
    99 	/* makes hash[COOKIE=20] from stralloc *indata, ignoring case and */
       
   100 	/* SPACE/TAB */
       
   101 {
       
   102   unsigned char h[32];
       
   103   surfpcs s;
       
   104   unsigned int seed[32];
       
   105   int i;
       
   106 
       
   107   for (i = 0;i < 32;++i) seed[i] = 0;
       
   108   surfpcs_init(&s,seed);
       
   109   surfpcs_addlc(&s,indata,inlen);
       
   110   surfpcs_out(&s,h);
       
   111   for (i = 0;i < 20;++i)
       
   112     hash[i] = 'a' + (h[i] & 15);
       
   113 }
       
   114 
       
   115 unsigned int subhashb(const char *s,long len)
       
   116 {
       
   117   unsigned long h;
       
   118   h = 5381;
       
   119   while (len-- > 0)
       
   120     h = (h + (h << 5)) ^ (unsigned int)*s++;
       
   121   return h % 53;
       
   122 }
       
   123 
       
   124 unsigned int subhashs(const char *s)
       
   125 {
       
   126   return subhashb(s,strlen(s));
       
   127 }
       
   128 
       
   129 /* end copy of ezmlm-idx source */
       
   130 
       
   131 
       
   132 
       
   133 
       
   134 /*
       
   135  * call­seq:
       
   136  *   Ezmlm::Hash.address( email ) -> String
       
   137  *
       
   138  * Call the Surf hashing function on an +email+ address, returning
       
   139  * the hashed string.  This is specific to how ezmlm is seeding
       
   140  * the hash, and parsing email addresses from messages (prefixed with
       
   141  * the '<' character.)
       
   142  *
       
   143  */
       
   144 VALUE
       
   145 address( VALUE klass, VALUE email ) {
       
   146 	char hash[20];
       
   147 	char *input;
       
   148 
       
   149 	Check_Type( email, T_STRING );
       
   150 
       
   151 	email = rb_str_plus( rb_str_new2("<"), email);
       
   152 	input = StringValueCStr( email );
       
   153 
       
   154 	makehash( input, strlen(input), hash );
       
   155 
       
   156 	return rb_str_new2( hash );
       
   157 }
       
   158 
       
   159 
       
   160 /*
       
   161  * call­seq:
       
   162  *   Ezmlm::Hash.subscriber( address ) -> String
       
   163  *
       
   164  * Call the subscriber hashing function on an email +address+, returning
       
   165  * the index character referring to the file containing subscriber presence.
       
   166  *
       
   167  */
       
   168 VALUE
       
   169 subscriber( VALUE klass, VALUE email ) {
       
   170 	unsigned int prefix;
       
   171 
       
   172 	Check_Type( email, T_STRING );
       
   173 
       
   174 	email  = rb_str_plus( rb_str_new2("T"), email);
       
   175 	prefix = subhashs( StringValueCStr(email) ) + 64;
       
   176 
       
   177 	return rb_sprintf( "%c", (char)prefix );
       
   178 }
       
   179 
       
   180 
       
   181 
       
   182 void
       
   183 Init_hash()
       
   184 {
       
   185 	rb_mEzmlm  = rb_define_module( "Ezmlm" );
       
   186 	rb_cEZHash = rb_define_class_under( rb_mEzmlm, "Hash", rb_cObject );
       
   187 
       
   188 	rb_define_module_function( rb_cEZHash, "address", address, 1 );
       
   189 	rb_define_module_function( rb_cEZHash, "subscriber", subscriber, 1 );
       
   190 
       
   191 	return;
       
   192 }
       
   193