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.8 by root, Wed Jul 22 10:33:08 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 XULONG;
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 XULONG; /* 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 (U32 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 U32 digest[5]; /* message digest */
51 ULONG count; /* 32-bit bit count */ 110 U32 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 U32 A, B, C, D, E, W[80], *restrict WP;
158 XULONG T;
113 159
114 dp = sha_info->data; 160 dp = sha_info->data;
115 161
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 162#if BYTEORDER == 0x1234
125#define SWAP_DONE
126 assert(sizeof(ULONG) == 4); 163 assert(sizeof(XULONG) == 4);
164# ifdef HAS_NTOHL
127 for (i = 0; i < 16; ++i) { 165 for (i = 0; i < 16; ++i) {
128 T = *((ULONG *) dp); 166 T = *((XULONG *) dp);
167 dp += 4;
168 W[i] = ntohl (T);
169 }
170# else
171 for (i = 0; i < 16; ++i) {
172 T = *((XULONG *) dp);
129 dp += 4; 173 dp += 4;
130 W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) | 174 W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) |
131 ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff); 175 ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
132 } 176 }
133#endif 177# endif
134
135#if BYTEORDER == 0x4321 178#elif BYTEORDER == 0x4321
136#define SWAP_DONE
137 assert(sizeof(ULONG) == 4); 179 assert(sizeof(XULONG) == 4);
138 for (i = 0; i < 16; ++i) { 180 for (i = 0; i < 16; ++i) {
139 T = *((ULONG *) dp); 181 T = *((XULONG *) dp);
140 dp += 4; 182 dp += 4;
141 W[i] = T32(T); 183 W[i] = T32(T);
142 } 184 }
143#endif
144
145#if BYTEORDER == 0x12345678 185#elif BYTEORDER == 0x12345678
146#define SWAP_DONE
147 assert(sizeof(ULONG) == 8); 186 assert(sizeof(XULONG) == 8);
148 for (i = 0; i < 16; i += 2) { 187 for (i = 0; i < 16; i += 2) {
149 T = *((ULONG *) dp); 188 T = *((XULONG *) dp);
150 dp += 8; 189 dp += 8;
151 W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) | 190 W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) |
152 ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff); 191 ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
153 T >>= 32; 192 T >>= 32;
154 W[i+1] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) | 193 W[i+1] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) |
155 ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff); 194 ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
156 } 195 }
157#endif
158
159#if BYTEORDER == 0x87654321 196#elif BYTEORDER == 0x87654321
160#define SWAP_DONE
161 assert(sizeof(ULONG) == 8); 197 assert(sizeof(XULONG) == 8);
162 for (i = 0; i < 16; i += 2) { 198 for (i = 0; i < 16; i += 2) {
163 T = *((ULONG *) dp); 199 T = *((XULONG *) dp);
164 dp += 8; 200 dp += 8;
165 W[i] = T32(T >> 32); 201 W[i] = T32(T >> 32);
166 W[i+1] = T32(T); 202 W[i+1] = T32(T);
167 } 203 }
168#endif 204#else
169
170#ifndef SWAP_DONE
171#error Unknown byte order -- you need to add code here 205#error Unknown byte order -- you need to add code here
172#endif /* SWAP_DONE */ 206#endif
173 207
174 for (i = 16; i < 80; ++i) { 208 for (i = 16; i < 80; ++i)
209 {
175 W[i] = W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]; 210 T = W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16];
176#if (SHA_VERSION == 1) 211 W[i] = R32(T,1);
177 W[i] = R32(W[i], 1);
178#endif /* SHA_VERSION */
179 } 212 }
213
180 A = sha_info->digest[0]; 214 A = sha_info->digest[0];
181 B = sha_info->digest[1]; 215 B = sha_info->digest[1];
182 C = sha_info->digest[2]; 216 C = sha_info->digest[2];
183 D = sha_info->digest[3]; 217 D = sha_info->digest[3];
184 E = sha_info->digest[4]; 218 E = sha_info->digest[4];
219
185 WP = W; 220 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); 221 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); 222 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); 223 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); 224 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); 225 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); 226 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); 227 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); 228 FE(4); FT(4); FA(4); FB(4); FC(4); FD(4); FE(4); FT(4); FA(4); FB(4);
229
195 sha_info->digest[0] = T32(sha_info->digest[0] + E); 230 sha_info->digest[0] = T32(sha_info->digest[0] + E);
196 sha_info->digest[1] = T32(sha_info->digest[1] + T); 231 sha_info->digest[1] = T32(sha_info->digest[1] + T);
197 sha_info->digest[2] = T32(sha_info->digest[2] + A); 232 sha_info->digest[2] = T32(sha_info->digest[2] + A);
198 sha_info->digest[3] = T32(sha_info->digest[3] + B); 233 sha_info->digest[3] = T32(sha_info->digest[3] + B);
199 sha_info->digest[4] = T32(sha_info->digest[4] + C); 234 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} 235}
223 236
224/* initialize the SHA digest */ 237/* initialize the SHA digest */
225 238
226static void sha_init(restrict SHA_INFO *sha_info) 239static void sha_init(SHA_INFO *restrict sha_info)
227{ 240{
228 sha_info->digest[0] = 0x67452301L; 241 sha_info->digest[0] = 0x67452301L;
229 sha_info->digest[1] = 0xefcdab89L; 242 sha_info->digest[1] = 0xefcdab89L;
230 sha_info->digest[2] = 0x98badcfeL; 243 sha_info->digest[2] = 0x98badcfeL;
231 sha_info->digest[3] = 0x10325476L; 244 sha_info->digest[3] = 0x10325476L;
234 sha_info->local = 0; 247 sha_info->local = 0;
235} 248}
236 249
237/* update the SHA digest */ 250/* update the SHA digest */
238 251
239static void sha_update(restrict SHA_INFO *sha_info, restrict U8 *buffer, int count) 252static void sha_update(SHA_INFO *restrict sha_info, U8 *restrict buffer, int count)
240{ 253{
241 int i; 254 int i;
242 255
243 sha_info->count += count << 3; 256 sha_info->count += count;
244 if (sha_info->local) { 257 if (sha_info->local) {
245 i = SHA_BLOCKSIZE - sha_info->local; 258 i = SHA_BLOCKSIZE - sha_info->local;
246 if (i > count) { 259 if (i > count) {
247 i = count; 260 i = count;
248 } 261 }
264 } 277 }
265 memcpy(sha_info->data, buffer, count); 278 memcpy(sha_info->data, buffer, count);
266 sha_info->local = count; 279 sha_info->local = count;
267} 280}
268 281
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 */ 282/* finish computing the SHA digest */
299static void sha_final(SHA_INFO *sha_info) 283static int sha_final(SHA_INFO *sha_info)
300{ 284{
301 int count;
302 U32 bit_count;
303
304 bit_count = sha_info->count; 285 int count = sha_info->count;
305 count = (int) ((bit_count >> 3) & 0x3f); 286 int local = sha_info->local;
306 ((U8 *) sha_info->data)[count++] = 0x80;
307 287
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; 288 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 289
290 if (sha_info->local >= SHA_BLOCKSIZE - 8) {
291 memset(sha_info->data + local + 1, 0, SHA_BLOCKSIZE - 1 - local);
325 sha_transform (sha_info); 292 sha_transform(sha_info);
293 memset(sha_info->data, 0, SHA_BLOCKSIZE - 2);
294 } else {
295 memset(sha_info->data + local + 1, 0, SHA_BLOCKSIZE - 3 - local);
296 }
297
298 sha_info->data[62] = count >> 5;
299 sha_info->data[63] = count << 3;
300
301 sha_transform (sha_info);
302
303 return sha_info->digest[0]
304 ? zprefix (sha_info->digest[0])
305 : zprefix (sha_info->digest[1]) + 32;
326} 306}
327 307
328#define TRIALCHAR "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%&()*+,-./;<=>?@[]{}^_|" 308#define TRIALCHAR "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%&()*+,-./;<=>?@[]{}^_|"
329 309
330static char nextenc[256]; 310static char
311nextenc[256];
331 312
332static char rand_char () 313static char
314rand_char ()
333{ 315{
334 return TRIALCHAR[rand () % sizeof (TRIALCHAR)]; 316 return TRIALCHAR[(int)(Drand01 () * sizeof (TRIALCHAR))];
335} 317}
336 318
337static int zprefix (ULONG n) 319typedef 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 320
359 return 321static double
360 n > 0xffffff ? zp[n >> 24] 322simple_nvtime (void)
361 : n > 0xffff ? 8 + zp[n >> 16] 323{
362 : n > 0xff ? 16 + zp[n >> 8] 324 return time (0);
363 : 24 + zp[n]; 325}
326
327static NVTime
328get_nvtime (void)
329{
330 SV **svp = hv_fetch (PL_modglobal, "Time::NVtime", 12, 0);
331
332 if (svp && SvIOK(*svp))
333 return INT2PTR(NVTime, SvIV(*svp));
334 else
335 return simple_nvtime;
336
364} 337}
365 338
366MODULE = Digest::Hashcash PACKAGE = Digest::Hashcash 339MODULE = Digest::Hashcash PACKAGE = Digest::Hashcash
367 340
368BOOT: 341BOOT:
373 nextenc[TRIALCHAR[i]] = TRIALCHAR[(i + 1) % sizeof (TRIALCHAR)]; 346 nextenc[TRIALCHAR[i]] = TRIALCHAR[(i + 1) % sizeof (TRIALCHAR)];
374} 347}
375 348
376PROTOTYPES: ENABLE 349PROTOTYPES: ENABLE
377 350
378int 351# could be improved quite a bit in accuracy
379_estimate_time (float seconds = 2, float minfactor = 1) 352NV
353_estimate_rounds ()
380 CODE: 354 CODE:
381 RETVAL = minfactor; 355{
356 char data[40];
357 NVTime nvtime = get_nvtime ();
358 NV t1, t2, t;
359 int count = 0;
360 SHA_INFO ctx;
361
362 t = nvtime ();
363 do {
364 t1 = nvtime ();
365 } while (t == t1);
366
367 t = t2 = nvtime ();
368 do {
369 volatile int i;
370 sha_init (&ctx);
371 sha_update (&ctx, data, sizeof (data));
372 i = sha_final (&ctx);
373
374 if (!(++count & 1023))
375 t2 = nvtime ();
376
377 } while (t == t2);
378
379 RETVAL = (NV)count / (t2 - t1);
380}
382 OUTPUT: 381 OUTPUT:
383 RETVAL 382 RETVAL
384 383
385SV * 384SV *
386_gentoken (int collisions, IV timestamp, char *resource, char *trial = "", int extrarand = 0) 385_gentoken (int size, IV timestamp, char *resource, char *trial = "", int extrarand = 0)
387 CODE: 386 CODE:
387{
388 SHA_INFO ctx1, ctx; 388 SHA_INFO ctx1, ctx;
389 char *token, *seq, *s; 389 char *token, *seq, *s;
390 int toklen, i; 390 int toklen, i;
391 time_t tstamp = timestamp ? timestamp : time (0); 391 time_t tstamp = timestamp ? timestamp : time (0);
392 struct tm *tm = gmtime (&tstamp); 392 struct tm *tm = gmtime (&tstamp);
393 393
394 New (0, token, 394 New (0, token,
395 1 + 1 // version 395 1 + 1 // version
396 + 12 + 1 // time field sans century 396 + 12 + 1 // time field sans century
397 + strlen (resource) + 1 // ressource 397 + strlen (resource) + 1 // ressource
398 + strlen (trial) + extrarand + 8 + 1 // trial 398 + strlen (trial) + extrarand + 8 + 1 // trial
399 + 1, 399 + 1,
400 char); 400 char);
401 401
402 if (!token) 402 if (!token)
403 croak ("out of memory"); 403 croak ("out of memory");
404 404
405 if (collisions > 32) 405 if (size > 64)
406 croak ("collisions must be <= 32 in this implementation\n"); 406 croak ("size must be <= 64 in this implementation\n");
407 407
408 toklen = sprintf (token, "%d:%02d%02d%02d%02d%02d%02d:%s:%s", 408 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, 409 0, tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday,
410 tm->tm_hour, tm->tm_min, tm->tm_sec, 410 tm->tm_hour, tm->tm_min, tm->tm_sec,
411 resource, trial); 411 resource, trial);
412 412
413 if (toklen > 8000)
414 croak ("token length must be <= 8000 in this implementation\n");
415
416 perlinterp_release ();
417
413 i = toklen + extrarand; 418 i = toklen + extrarand;
414 while (toklen < i) 419 while (toklen < i)
415 token[toklen++] = rand_char (); 420 token[toklen++] = rand_char ();
416 421
417 sha_init (&ctx1); 422 sha_init (&ctx1);
424 429
425 for (;;) 430 for (;;)
426 { 431 {
427 ctx = ctx1; // this "optimization" can help a lot for longer resource strings 432 ctx = ctx1; // this "optimization" can help a lot for longer resource strings
428 sha_update (&ctx, seq, 8); 433 sha_update (&ctx, seq, 8);
429 sha_final (&ctx); 434 i = sha_final (&ctx);
430 435
431 i = zprefix (ctx.digest[0]);
432
433 if (i >= collisions) 436 if (i >= size)
434 break; 437 break;
435 438
436 s = seq; 439 s = seq;
437 do { 440 do {
438 *s = nextenc [*s]; 441 *s = nextenc [*s];
439 } while (*s++ == 'a'); 442 } while (*s++ == 'a');
440 } 443 }
441 444
445 perlinterp_acquire ();
446
442 RETVAL = newSVpvn (token, toklen); 447 RETVAL = newSVpvn (token, toklen);
448}
443 OUTPUT: 449 OUTPUT:
444 RETVAL 450 RETVAL
445 451
446int 452int
447_prefixlen (SV *tok) 453_prefixlen (SV *tok)
448 CODE: 454 CODE:
455{
449 STRLEN toklen; 456 STRLEN toklen;
450 char *token = SvPV (tok, toklen); 457 char *token = SvPV (tok, toklen);
451 SHA_INFO ctx; 458 SHA_INFO ctx;
452 459
453 sha_init (&ctx); 460 sha_init (&ctx);
454 sha_update (&ctx, token, toklen); 461 sha_update (&ctx, token, toklen);
455 sha_final (&ctx); 462 RETVAL = sha_final (&ctx);
456 463}
457 RETVAL = zprefix (ctx.digest[0]);
458 OUTPUT: 464 OUTPUT:
459 RETVAL 465 RETVAL
460 466
461 467

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines