|
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 |