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.7 by root, Tue Jul 21 05:01:01 2015 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines