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.4 by root, Mon Oct 20 04:17:05 2003 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines