ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Digest-Hashcash/Hashcash.xs
(Generate patch)

Comparing Digest-Hashcash/Hashcash.xs (file contents):
Revision 1.1 by root, Sat Sep 6 22:12:00 2003 UTC vs.
Revision 1.6 by root, Sun Jun 27 13:30:43 2004 UTC

19 * kept me from doing it, so here's the truth: I took this code from the 19 * kept me from doing it, so here's the truth: I took this code from the
20 * SHA1 perl module, since it looked reasonably well-crafted. I modified 20 * SHA1 perl module, since it looked reasonably well-crafted. I modified
21 * it here and there, though. 21 * it here and there, though.
22 */ 22 */
23 23
24/*
25 * we have lots of micro-optimizations here, this is just for toying
26 * around...
27 */
28
24/* don't expect _too_ much from compilers for now. */ 29/* don't expect _too_ much from compilers for now. */
25#if __GNUC_MAJOR > 2 30#if __GNUC__ > 2
26# define restrict __restrict__ 31# define restrict __restrict__
32# define inline __inline__
33# ifdef __i386
34# define GCCX86ASM 1
35# endif
27#elif __STDC_VERSION__ < 199900 36#elif __STDC_VERSION__ < 199900
28# define restrict 37# define restrict
38# define inline
29#endif 39#endif
40
41#if __GNUC__ < 2
42# define __attribute__(x)
43#endif
44
45#ifdef __i386
46# define a_regparm(n) __attribute__((__regparm__(n)))
47#else
48# define a_regparm(n)
49#endif
50
51#define a_const __attribute__((__const__))
30 52
31/* Useful defines & typedefs */ 53/* Useful defines & typedefs */
32 54
33#if defined(U64TYPE) && (defined(USE_64_BIT_INT) || ((BYTEORDER != 0x1234) && (BYTEORDER != 0x4321))) 55#if defined(U64TYPE) && (defined(USE_64_BIT_INT) || ((BYTEORDER != 0x1234) && (BYTEORDER != 0x4321)))
34typedef U64TYPE ULONG; 56typedef U64TYPE ULONG;
35# if BYTEORDER == 0x1234 57# if BYTEORDER == 0x1234
36# undef BYTEORDER 58# undef BYTEORDER
37# define BYTEORDER 0x12345678 59# define BYTEORDER 0x12345678
38# elif BYTEORDER == 0x4321 60# elif BYTEORDER == 0x4321
39# undef BYTEORDER 61# undef BYTEORDER
40# define BYTEORDER 0x87654321 62# define BYTEORDER 0x87654321
41# endif 63# endif
42#else 64#else
43typedef uint_fast32_t ULONG; /* 32-or-more-bit quantity */ 65typedef uint_fast32_t ULONG; /* 32-or-more-bit quantity */
66#endif
67
68#if GCCX86ASM
69# define zprefix(n) ({ int _r; __asm__ ("bsrl %1, %0" : "=r" (_r) : "r" (n)); 31 - _r ; })
70#elif __GNUC__ > 2 && __GNUC_MINOR__ > 3
71# define zprefix(n) (__extension__ ({ uint32_t n__ = (n); n ? __builtin_clz (n) : 32; }))
72#else
73static int a_const zprefix (ULONG n)
74{
75 static char zp[256] =
76 {
77 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
78 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
79 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
80 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
81 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
82 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
83 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
84 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
85 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
86 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
87 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
88 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
89 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
90 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
91 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
92 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
93 };
94
95 return
96 n > 0xffffff ? zp[n >> 24]
97 : n > 0xffff ? 8 + zp[n >> 16]
98 : n > 0xff ? 16 + zp[n >> 8]
99 : 24 + zp[n];
100}
44#endif 101#endif
45 102
46#define SHA_BLOCKSIZE 64 103#define SHA_BLOCKSIZE 64
47#define SHA_DIGESTSIZE 20 104#define SHA_DIGESTSIZE 20
48 105
49typedef struct { 106typedef struct {
50 ULONG digest[5]; /* message digest */ 107 ULONG digest[5]; /* message digest */
51 ULONG count; /* 32-bit bit count */ 108 ULONG count; /* 32-bit bit count */
109 int local; /* unprocessed amount in data */
52 U8 data[SHA_BLOCKSIZE]; /* SHA data buffer */ 110 U8 data[SHA_BLOCKSIZE]; /* SHA data buffer */
53 int local; /* unprocessed amount in data */
54} SHA_INFO; 111} SHA_INFO;
55 112
56
57/* UNRAVEL should be fastest & biggest */
58/* UNROLL_LOOPS should be just as big, but slightly slower */
59/* both undefined should be smallest and slowest */
60
61#define SHA_VERSION 1
62#define UNRAVEL
63/* #define UNROLL_LOOPS */
64 113
65/* SHA f()-functions */ 114/* SHA f()-functions */
66#define f1(x,y,z) ((x & y) | (~x & z)) 115#define f1(x,y,z) ((x & y) | (~x & z))
67#define f2(x,y,z) (x ^ y ^ z) 116#define f2(x,y,z) (x ^ y ^ z)
68#define f3(x,y,z) ((x & y) | (x & z) | (y & z)) 117#define f3(x,y,z) ((x & y) | (x & z) | (y & z))
78#define T32(x) ((x) & 0xffffffffL) 127#define T32(x) ((x) & 0xffffffffL)
79 128
80/* 32-bit rotate */ 129/* 32-bit rotate */
81#define R32(x,n) T32(((x << n) | (x >> (32 - n)))) 130#define R32(x,n) T32(((x << n) | (x >> (32 - n))))
82 131
83/* the generic case, for when the overall rotation is not unraveled */
84#define FG(n) \
85 T = T32(R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n); \
86 E = D; D = C; C = R32(B,30); B = A; A = T
87
88/* specific cases, for when the overall rotation is unraveled */ 132/* specific cases, for when the overall rotation is unraveled */
89#define FA(n) \ 133#define FA(n) \
90 T = T32(R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n); B = R32(B,30) 134 T = T32(R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n); B = R32(B,30)
91 135
92#define FB(n) \ 136#define FB(n) \
102 B = T32(R32(C,5) + f##n(D,E,T) + A + *WP++ + CONST##n); D = R32(D,30) 146 B = T32(R32(C,5) + f##n(D,E,T) + A + *WP++ + CONST##n); D = R32(D,30)
103 147
104#define FT(n) \ 148#define FT(n) \
105 A = T32(R32(B,5) + f##n(C,D,E) + T + *WP++ + CONST##n); C = R32(C,30) 149 A = T32(R32(B,5) + f##n(C,D,E) + T + *WP++ + CONST##n); C = R32(C,30)
106 150
107 151static void a_regparm(1) sha_transform(SHA_INFO *restrict sha_info)
108static void sha_transform(restrict SHA_INFO *sha_info)
109{ 152{
110 int i; 153 int i;
111 U8 *dp; 154 U8 *restrict dp;
112 ULONG T, A, B, C, D, E, W[80], *WP; 155 ULONG T, A, B, C, D, E, W[80], *restrict WP;
113 156
114 dp = sha_info->data; 157 dp = sha_info->data;
115 158
116/*
117the following makes sure that at least one code block below is
118traversed or an error is reported, without the necessity for nested
119preprocessor if/else/endif blocks, which are a great pain in the
120nether regions of the anatomy...
121*/
122#undef SWAP_DONE
123
124#if BYTEORDER == 0x1234 159#if BYTEORDER == 0x1234
125#define SWAP_DONE
126 assert(sizeof(ULONG) == 4); 160 assert(sizeof(ULONG) == 4);
161# ifdef HAS_NTOHL
162 for (i = 0; i < 16; ++i) {
163 T = *((ULONG *) dp);
164 dp += 4;
165 W[i] = ntohl (T);
166 }
167# else
127 for (i = 0; i < 16; ++i) { 168 for (i = 0; i < 16; ++i) {
128 T = *((ULONG *) dp); 169 T = *((ULONG *) dp);
129 dp += 4; 170 dp += 4;
130 W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) | 171 W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) |
131 ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff); 172 ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
132 } 173 }
133#endif 174# endif
134
135#if BYTEORDER == 0x4321 175#elif BYTEORDER == 0x4321
136#define SWAP_DONE
137 assert(sizeof(ULONG) == 4); 176 assert(sizeof(ULONG) == 4);
138 for (i = 0; i < 16; ++i) { 177 for (i = 0; i < 16; ++i) {
139 T = *((ULONG *) dp); 178 T = *((ULONG *) dp);
140 dp += 4; 179 dp += 4;
141 W[i] = T32(T); 180 W[i] = T32(T);
142 } 181 }
143#endif
144
145#if BYTEORDER == 0x12345678 182#elif BYTEORDER == 0x12345678
146#define SWAP_DONE
147 assert(sizeof(ULONG) == 8); 183 assert(sizeof(ULONG) == 8);
148 for (i = 0; i < 16; i += 2) { 184 for (i = 0; i < 16; i += 2) {
149 T = *((ULONG *) dp); 185 T = *((ULONG *) dp);
150 dp += 8; 186 dp += 8;
151 W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) | 187 W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) |
152 ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff); 188 ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
153 T >>= 32; 189 T >>= 32;
154 W[i+1] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) | 190 W[i+1] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) |
155 ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff); 191 ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
156 } 192 }
157#endif
158
159#if BYTEORDER == 0x87654321 193#elif BYTEORDER == 0x87654321
160#define SWAP_DONE
161 assert(sizeof(ULONG) == 8); 194 assert(sizeof(ULONG) == 8);
162 for (i = 0; i < 16; i += 2) { 195 for (i = 0; i < 16; i += 2) {
163 T = *((ULONG *) dp); 196 T = *((ULONG *) dp);
164 dp += 8; 197 dp += 8;
165 W[i] = T32(T >> 32); 198 W[i] = T32(T >> 32);
166 W[i+1] = T32(T); 199 W[i+1] = T32(T);
167 } 200 }
168#endif 201#else
169
170#ifndef SWAP_DONE
171#error Unknown byte order -- you need to add code here 202#error Unknown byte order -- you need to add code here
172#endif /* SWAP_DONE */ 203#endif
173 204
174 for (i = 16; i < 80; ++i) { 205 for (i = 16; i < 80; ++i)
206 {
175 W[i] = W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]; 207 T = W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16];
176#if (SHA_VERSION == 1) 208 W[i] = R32(T,1);
177 W[i] = R32(W[i], 1);
178#endif /* SHA_VERSION */
179 } 209 }
210
180 A = sha_info->digest[0]; 211 A = sha_info->digest[0];
181 B = sha_info->digest[1]; 212 B = sha_info->digest[1];
182 C = sha_info->digest[2]; 213 C = sha_info->digest[2];
183 D = sha_info->digest[3]; 214 D = sha_info->digest[3];
184 E = sha_info->digest[4]; 215 E = sha_info->digest[4];
216
185 WP = W; 217 WP = W;
186#ifdef UNRAVEL
187 FA(1); FB(1); FC(1); FD(1); FE(1); FT(1); FA(1); FB(1); FC(1); FD(1); 218 FA(1); FB(1); FC(1); FD(1); FE(1); FT(1); FA(1); FB(1); FC(1); FD(1);
188 FE(1); FT(1); FA(1); FB(1); FC(1); FD(1); FE(1); FT(1); FA(1); FB(1); 219 FE(1); FT(1); FA(1); FB(1); FC(1); FD(1); FE(1); FT(1); FA(1); FB(1);
189 FC(2); FD(2); FE(2); FT(2); FA(2); FB(2); FC(2); FD(2); FE(2); FT(2); 220 FC(2); FD(2); FE(2); FT(2); FA(2); FB(2); FC(2); FD(2); FE(2); FT(2);
190 FA(2); FB(2); FC(2); FD(2); FE(2); FT(2); FA(2); FB(2); FC(2); FD(2); 221 FA(2); FB(2); FC(2); FD(2); FE(2); FT(2); FA(2); FB(2); FC(2); FD(2);
191 FE(3); FT(3); FA(3); FB(3); FC(3); FD(3); FE(3); FT(3); FA(3); FB(3); 222 FE(3); FT(3); FA(3); FB(3); FC(3); FD(3); FE(3); FT(3); FA(3); FB(3);
192 FC(3); FD(3); FE(3); FT(3); FA(3); FB(3); FC(3); FD(3); FE(3); FT(3); 223 FC(3); FD(3); FE(3); FT(3); FA(3); FB(3); FC(3); FD(3); FE(3); FT(3);
193 FA(4); FB(4); FC(4); FD(4); FE(4); FT(4); FA(4); FB(4); FC(4); FD(4); 224 FA(4); FB(4); FC(4); FD(4); FE(4); FT(4); FA(4); FB(4); FC(4); FD(4);
194 FE(4); FT(4); FA(4); FB(4); FC(4); FD(4); FE(4); FT(4); FA(4); FB(4); 225 FE(4); FT(4); FA(4); FB(4); FC(4); FD(4); FE(4); FT(4); FA(4); FB(4);
226
195 sha_info->digest[0] = T32(sha_info->digest[0] + E); 227 sha_info->digest[0] = T32(sha_info->digest[0] + E);
196 sha_info->digest[1] = T32(sha_info->digest[1] + T); 228 sha_info->digest[1] = T32(sha_info->digest[1] + T);
197 sha_info->digest[2] = T32(sha_info->digest[2] + A); 229 sha_info->digest[2] = T32(sha_info->digest[2] + A);
198 sha_info->digest[3] = T32(sha_info->digest[3] + B); 230 sha_info->digest[3] = T32(sha_info->digest[3] + B);
199 sha_info->digest[4] = T32(sha_info->digest[4] + C); 231 sha_info->digest[4] = T32(sha_info->digest[4] + C);
200#else /* !UNRAVEL */
201#ifdef UNROLL_LOOPS
202 FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1);
203 FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1);
204 FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2);
205 FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2);
206 FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3);
207 FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3);
208 FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4);
209 FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4);
210#else /* !UNROLL_LOOPS */
211 for (i = 0; i < 20; ++i) { FG(1); }
212 for (i = 20; i < 40; ++i) { FG(2); }
213 for (i = 40; i < 60; ++i) { FG(3); }
214 for (i = 60; i < 80; ++i) { FG(4); }
215#endif /* !UNROLL_LOOPS */
216 sha_info->digest[0] = T32(sha_info->digest[0] + A);
217 sha_info->digest[1] = T32(sha_info->digest[1] + B);
218 sha_info->digest[2] = T32(sha_info->digest[2] + C);
219 sha_info->digest[3] = T32(sha_info->digest[3] + D);
220 sha_info->digest[4] = T32(sha_info->digest[4] + E);
221#endif /* !UNRAVEL */
222} 232}
223 233
224/* initialize the SHA digest */ 234/* initialize the SHA digest */
225 235
226static void sha_init(restrict SHA_INFO *sha_info) 236static void sha_init(SHA_INFO *restrict sha_info)
227{ 237{
228 sha_info->digest[0] = 0x67452301L; 238 sha_info->digest[0] = 0x67452301L;
229 sha_info->digest[1] = 0xefcdab89L; 239 sha_info->digest[1] = 0xefcdab89L;
230 sha_info->digest[2] = 0x98badcfeL; 240 sha_info->digest[2] = 0x98badcfeL;
231 sha_info->digest[3] = 0x10325476L; 241 sha_info->digest[3] = 0x10325476L;
234 sha_info->local = 0; 244 sha_info->local = 0;
235} 245}
236 246
237/* update the SHA digest */ 247/* update the SHA digest */
238 248
239static void sha_update(restrict SHA_INFO *sha_info, restrict U8 *buffer, int count) 249static void sha_update(SHA_INFO *restrict sha_info, U8 *restrict buffer, int count)
240{ 250{
241 int i; 251 int i;
242 252
243 sha_info->count += count << 3; 253 sha_info->count += count;
244 if (sha_info->local) { 254 if (sha_info->local) {
245 i = SHA_BLOCKSIZE - sha_info->local; 255 i = SHA_BLOCKSIZE - sha_info->local;
246 if (i > count) { 256 if (i > count) {
247 i = count; 257 i = count;
248 } 258 }
264 } 274 }
265 memcpy(sha_info->data, buffer, count); 275 memcpy(sha_info->data, buffer, count);
266 sha_info->local = count; 276 sha_info->local = count;
267} 277}
268 278
269
270#if 0
271static void sha_transform_and_copy (unsigned char digest[20], restrict SHA_INFO *sha_info)
272{
273 sha_transform (sha_info);
274
275 digest[ 0] = (unsigned char) ((sha_info->digest[0] >> 24) & 0xff);
276 digest[ 1] = (unsigned char) ((sha_info->digest[0] >> 16) & 0xff);
277 digest[ 2] = (unsigned char) ((sha_info->digest[0] >> 8) & 0xff);
278 digest[ 3] = (unsigned char) ((sha_info->digest[0] ) & 0xff);
279 digest[ 4] = (unsigned char) ((sha_info->digest[1] >> 24) & 0xff);
280 digest[ 5] = (unsigned char) ((sha_info->digest[1] >> 16) & 0xff);
281 digest[ 6] = (unsigned char) ((sha_info->digest[1] >> 8) & 0xff);
282 digest[ 7] = (unsigned char) ((sha_info->digest[1] ) & 0xff);
283 digest[ 8] = (unsigned char) ((sha_info->digest[2] >> 24) & 0xff);
284 digest[ 9] = (unsigned char) ((sha_info->digest[2] >> 16) & 0xff);
285 digest[10] = (unsigned char) ((sha_info->digest[2] >> 8) & 0xff);
286 digest[11] = (unsigned char) ((sha_info->digest[2] ) & 0xff);
287 digest[12] = (unsigned char) ((sha_info->digest[3] >> 24) & 0xff);
288 digest[13] = (unsigned char) ((sha_info->digest[3] >> 16) & 0xff);
289 digest[14] = (unsigned char) ((sha_info->digest[3] >> 8) & 0xff);
290 digest[15] = (unsigned char) ((sha_info->digest[3] ) & 0xff);
291 digest[16] = (unsigned char) ((sha_info->digest[4] >> 24) & 0xff);
292 digest[17] = (unsigned char) ((sha_info->digest[4] >> 16) & 0xff);
293 digest[18] = (unsigned char) ((sha_info->digest[4] >> 8) & 0xff);
294 digest[19] = (unsigned char) ((sha_info->digest[4] ) & 0xff);
295}
296#endif
297
298/* finish computing the SHA digest */ 279/* finish computing the SHA digest */
299static void sha_final(SHA_INFO *sha_info) 280static int sha_final(SHA_INFO *sha_info)
300{ 281{
301 int count;
302 U32 bit_count;
303
304 bit_count = sha_info->count; 282 int count = sha_info->count;
305 count = (int) ((bit_count >> 3) & 0x3f); 283 int local = sha_info->local;
306 ((U8 *) sha_info->data)[count++] = 0x80;
307 284
308 if (count > SHA_BLOCKSIZE - 8) {
309 memset(((U8 *) sha_info->data) + count, 0, SHA_BLOCKSIZE - count);
310 sha_transform(sha_info);
311 memset((U8 *) sha_info->data, 0, SHA_BLOCKSIZE - 8);
312 } else {
313 memset(((U8 *) sha_info->data) + count, 0, SHA_BLOCKSIZE - 8 - count);
314 }
315
316 sha_info->data[56] = 0; 285 sha_info->data[local] = 0x80;
317 sha_info->data[57] = 0;
318 sha_info->data[58] = 0;
319 sha_info->data[59] = 0;
320 sha_info->data[60] = (bit_count >> 24) & 0xff;
321 sha_info->data[61] = (bit_count >> 16) & 0xff;
322 sha_info->data[62] = (bit_count >> 8) & 0xff;
323 sha_info->data[63] = (bit_count >> 0) & 0xff;
324 286
287 if (sha_info->local >= SHA_BLOCKSIZE - 8) {
288 memset(sha_info->data + local + 1, 0, SHA_BLOCKSIZE - 1 - local);
325 sha_transform (sha_info); 289 sha_transform(sha_info);
290 memset(sha_info->data, 0, SHA_BLOCKSIZE - 2);
291 } else {
292 memset(sha_info->data + local + 1, 0, SHA_BLOCKSIZE - 3 - local);
293 }
294
295 sha_info->data[62] = count >> 5;
296 sha_info->data[63] = count << 3;
297
298 sha_transform (sha_info);
299
300 return sha_info->digest[0]
301 ? zprefix (sha_info->digest[0])
302 : zprefix (sha_info->digest[1]) + 32;
326} 303}
327 304
328#define TRIALCHAR "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%&()*+,-./;<=>?@[]{}^_|" 305#define TRIALCHAR "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%&()*+,-./;<=>?@[]{}^_|"
329 306
330static char nextenc[256]; 307static char nextenc[256];
332static char rand_char () 309static char rand_char ()
333{ 310{
334 return TRIALCHAR[rand () % sizeof (TRIALCHAR)]; 311 return TRIALCHAR[rand () % sizeof (TRIALCHAR)];
335} 312}
336 313
337static int zprefix (ULONG n) 314typedef double (*NVTime)(void);
338{
339 static char zp[256] =
340 {
341 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
342 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
343 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
344 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
345 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
346 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
347 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
348 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
349 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
350 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
351 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
352 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
353 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
354 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
355 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
356 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
357 };
358 315
359 return 316static double simple_nvtime (void)
360 n > 0xffffff ? zp[n >> 24] 317{
361 : n > 0xffff ? 8 + zp[n >> 16] 318 return time (0);
362 : n > 0xff ? 16 + zp[n >> 8] 319}
363 : 24 + zp[n]; 320
321static NVTime get_nvtime (void)
322{
323 SV **svp = hv_fetch (PL_modglobal, "Time::NVtime", 12, 0);
324
325 if (svp && SvIOK(*svp))
326 return INT2PTR(NVTime, SvIV(*svp));
327 else
328 return simple_nvtime;
329
364} 330}
365 331
366MODULE = Digest::Hashcash PACKAGE = Digest::Hashcash 332MODULE = Digest::Hashcash PACKAGE = Digest::Hashcash
367 333
368BOOT: 334BOOT:
373 nextenc[TRIALCHAR[i]] = TRIALCHAR[(i + 1) % sizeof (TRIALCHAR)]; 339 nextenc[TRIALCHAR[i]] = TRIALCHAR[(i + 1) % sizeof (TRIALCHAR)];
374} 340}
375 341
376PROTOTYPES: ENABLE 342PROTOTYPES: ENABLE
377 343
378int 344# could be improved quite a bit in accuracy
379_estimate_time (float seconds = 2, float minfactor = 1) 345NV
346_estimate_rounds ()
380 CODE: 347 CODE:
381 RETVAL = minfactor; 348{
349 char data[40];
350 NVTime nvtime = get_nvtime ();
351 NV t1, t2, t;
352 int count = 0;
353 SHA_INFO ctx;
354
355 t = nvtime ();
356 do {
357 t1 = nvtime ();
358 } while (t == t1);
359
360 t = t2 = nvtime ();
361 do {
362 volatile int i;
363 sha_init (&ctx);
364 sha_update (&ctx, data, sizeof (data));
365 i = sha_final (&ctx);
366
367 if (!(++count & 1023))
368 t2 = nvtime ();
369
370 } while (t == t2);
371
372 RETVAL = (NV)count / (t2 - t1);
373}
382 OUTPUT: 374 OUTPUT:
383 RETVAL 375 RETVAL
384 376
385SV * 377SV *
386_gentoken (int collisions, IV timestamp, char *resource, char *trial = "", int extrarand = 0) 378_gentoken (int size, IV timestamp, char *resource, char *trial = "", int extrarand = 0)
387 CODE: 379 CODE:
380{
388 SHA_INFO ctx1, ctx; 381 SHA_INFO ctx1, ctx;
389 char *token, *seq, *s; 382 char *token, *seq, *s;
390 int toklen, i; 383 int toklen, i;
391 time_t tstamp = timestamp ? timestamp : time (0); 384 time_t tstamp = timestamp ? timestamp : time (0);
392 struct tm *tm = gmtime (&tstamp); 385 struct tm *tm = gmtime (&tstamp);
393 386
394 New (0, token, 387 New (0, token,
395 1 + 1 // version 388 1 + 1 // version
396 + 12 + 1 // time field sans century 389 + 12 + 1 // time field sans century
397 + strlen (resource) + 1 // ressource 390 + strlen (resource) + 1 // ressource
398 + strlen (trial) + extrarand + 8 + 1 // trial 391 + strlen (trial) + extrarand + 8 + 1 // trial
399 + 1, 392 + 1,
400 char); 393 char);
401 394
402 if (!token) 395 if (!token)
403 croak ("out of memory"); 396 croak ("out of memory");
404 397
405 if (collisions > 32) 398 if (size > 64)
406 croak ("collisions must be <= 32 in this implementation\n"); 399 croak ("size must be <= 64 in this implementation\n");
407 400
408 toklen = sprintf (token, "%d:%02d%02d%02d%02d%02d%02d:%s:%s", 401 toklen = sprintf (token, "%d:%02d%02d%02d%02d%02d%02d:%s:%s",
409 0, tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday, 402 0, tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday,
410 tm->tm_hour, tm->tm_min, tm->tm_sec, 403 tm->tm_hour, tm->tm_min, tm->tm_sec,
411 resource, trial); 404 resource, trial);
412 405
406 if (toklen > 8000)
407 croak ("token length must be <= 8000 in this implementation\n");
408
413 i = toklen + extrarand; 409 i = toklen + extrarand;
414 while (toklen < i) 410 while (toklen < i)
415 token[toklen++] = rand_char (); 411 token[toklen++] = rand_char ();
416 412
417 sha_init (&ctx1); 413 sha_init (&ctx1);
424 420
425 for (;;) 421 for (;;)
426 { 422 {
427 ctx = ctx1; // this "optimization" can help a lot for longer resource strings 423 ctx = ctx1; // this "optimization" can help a lot for longer resource strings
428 sha_update (&ctx, seq, 8); 424 sha_update (&ctx, seq, 8);
429 sha_final (&ctx); 425 i = sha_final (&ctx);
430 426
431 i = zprefix (ctx.digest[0]);
432
433 if (i >= collisions) 427 if (i >= size)
434 break; 428 break;
435 429
436 s = seq; 430 s = seq;
437 do { 431 do {
438 *s = nextenc [*s]; 432 *s = nextenc [*s];
439 } while (*s++ == 'a'); 433 } while (*s++ == 'a');
440 } 434 }
441 435
442 RETVAL = newSVpvn (token, toklen); 436 RETVAL = newSVpvn (token, toklen);
437}
443 OUTPUT: 438 OUTPUT:
444 RETVAL 439 RETVAL
445 440
446int 441int
447_prefixlen (SV *tok) 442_prefixlen (SV *tok)
448 CODE: 443 CODE:
444{
449 STRLEN toklen; 445 STRLEN toklen;
450 char *token = SvPV (tok, toklen); 446 char *token = SvPV (tok, toklen);
451 SHA_INFO ctx; 447 SHA_INFO ctx;
452 448
453 sha_init (&ctx); 449 sha_init (&ctx);
454 sha_update (&ctx, token, toklen); 450 sha_update (&ctx, token, toklen);
455 sha_final (&ctx); 451 RETVAL = sha_final (&ctx);
456 452}
457 RETVAL = zprefix (ctx.digest[0]);
458 OUTPUT: 453 OUTPUT:
459 RETVAL 454 RETVAL
460 455
461 456

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines