1 #define PERL_NO_GET_CONTEXT
2 #include "EXTERN.h"
3 #include "perl.h"
4 #include "XSUB.h"
5 
6 #ifdef SvPVbyte
7 	#if PERL_REVISION == 5 && PERL_VERSION < 8
8 		#undef SvPVbyte
9 		#define SvPVbyte(sv, lp) \
10 			(sv_utf8_downgrade((sv), 0), SvPV((sv), (lp)))
11 	#endif
12 #else
13 	#define SvPVbyte SvPV
14 #endif
15 
16 #ifndef dTHX
17 	#define pTHX_
18 	#define aTHX_
19 #endif
20 
21 #ifndef PerlIO
22 	#define PerlIO				FILE
23 	#define PerlIO_read(f, buf, count)	fread(buf, 1, count, f)
24 #endif
25 
26 #ifndef sv_derived_from
27 	#include "src/sdf.c"
28 #endif
29 
30 #ifndef Newx
31 	#define Newx(ptr, num, type)	New(0, ptr, num, type)
32 	#define Newxz(ptr, num, type)	Newz(0, ptr, num, type)
33 #endif
34 
35 #include "src/sha3.c"
36 
37 static const int ix2alg[] =
38 	{224,224,224,256,256,256,384,384,384,512,512,512,
39 	 128000,128000,128000,256000,256000,256000};
40 
41 #ifndef INT2PTR
42 #define INT2PTR(p, i) (p) (i)
43 #endif
44 
45 #define MAX_WRITE_SIZE 16384
46 #define IO_BUFFER_SIZE 4096
47 
getSHA3(pTHX_ SV * self)48 static SHA3 *getSHA3(pTHX_ SV *self)
49 {
50 	if (!sv_isobject(self) || !sv_derived_from(self, "Digest::SHA3"))
51 		return(NULL);
52 	return INT2PTR(SHA3 *, SvIV(SvRV(self)));
53 }
54 
55 MODULE = Digest::SHA3		PACKAGE = Digest::SHA3
56 
57 PROTOTYPES: ENABLE
58 
59 int
60 shainit(s, alg)
61 	SHA3 *	s
62 	int	alg
63 
64 void
65 sharewind(s)
66 	SHA3 *	s
67 
68 unsigned long
69 shawrite(bitstr, bitcnt, s)
70 	unsigned char *	bitstr
71 	unsigned long	bitcnt
72 	SHA3 *	s
73 
74 SV *
75 newSHA3(classname, alg)
76 	char *	classname
77 	int 	alg
78 PREINIT:
79 	SHA3 *state;
80 CODE:
81 	Newxz(state, 1, SHA3);
82 	if (!shainit(state, alg)) {
83 		Safefree(state);
84 		XSRETURN_UNDEF;
85 	}
86 	RETVAL = newSV(0);
87 	sv_setref_pv(RETVAL, classname, (void *) state);
88 	SvREADONLY_on(SvRV(RETVAL));
89 OUTPUT:
90 	RETVAL
91 
92 SV *
93 clone(self)
94 	SV *	self
95 PREINIT:
96 	SHA3 *state;
97 	SHA3 *clone;
98 CODE:
99 	if ((state = getSHA3(aTHX_ self)) == NULL)
100 		XSRETURN_UNDEF;
101 	Newx(clone, 1, SHA3);
102 	RETVAL = newSV(0);
103 	sv_setref_pv(RETVAL, sv_reftype(SvRV(self), 1), (void *) clone);
104 	SvREADONLY_on(SvRV(RETVAL));
105 	Copy(state, clone, 1, SHA3);
106 OUTPUT:
107 	RETVAL
108 
109 void
110 DESTROY(s)
111 	SHA3 *	s
112 CODE:
113 	Safefree(s);
114 
115 SV *
116 sha3_224(...)
117 ALIAS:
118 	Digest::SHA3::sha3_224 = 0
119 	Digest::SHA3::sha3_224_hex = 1
120 	Digest::SHA3::sha3_224_base64 = 2
121 	Digest::SHA3::sha3_256 = 3
122 	Digest::SHA3::sha3_256_hex = 4
123 	Digest::SHA3::sha3_256_base64 = 5
124 	Digest::SHA3::sha3_384 = 6
125 	Digest::SHA3::sha3_384_hex = 7
126 	Digest::SHA3::sha3_384_base64 = 8
127 	Digest::SHA3::sha3_512 = 9
128 	Digest::SHA3::sha3_512_hex = 10
129 	Digest::SHA3::sha3_512_base64 = 11
130 	Digest::SHA3::shake128 = 12
131 	Digest::SHA3::shake128_hex = 13
132 	Digest::SHA3::shake128_base64 = 14
133 	Digest::SHA3::shake256 = 15
134 	Digest::SHA3::shake256_hex = 16
135 	Digest::SHA3::shake256_base64 = 17
136 PREINIT:
137 	int i;
138 	UCHR *data;
139 	STRLEN len;
140 	SHA3 sha3;
141 	char *result;
142 CODE:
143 	if (!shainit(&sha3, ix2alg[ix]))
144 		XSRETURN_UNDEF;
145 	for (i = 0; i < items; i++) {
146 		data = (UCHR *) (SvPVbyte(ST(i), len));
147 		while (len > MAX_WRITE_SIZE) {
148 			shawrite(data, MAX_WRITE_SIZE << 3, &sha3);
149 			data += MAX_WRITE_SIZE;
150 			len  -= MAX_WRITE_SIZE;
151 		}
152 		shawrite(data, (ULNG) len << 3, &sha3);
153 	}
154 	shafinish(&sha3);
155 	len = 0;
156 	if (ix % 3 == 0) {
157 		result = (char *) shadigest(&sha3);
158 		len = (STRLEN) sha3.digestlen;
159 	}
160 	else if (ix % 3 == 1)
161 		result = shahex(&sha3);
162 	else
163 		result = shabase64(&sha3);
164 	RETVAL = newSVpv(result, len);
165 OUTPUT:
166 	RETVAL
167 
168 int
169 hashsize(self)
170 	SV *	self
171 ALIAS:
172 	Digest::SHA3::hashsize = 0
173 	Digest::SHA3::algorithm = 1
174 PREINIT:
175 	SHA3 *state;
176 CODE:
177 	if ((state = getSHA3(aTHX_ self)) == NULL)
178 		XSRETURN_UNDEF;
179 	RETVAL = ix ? state->alg : state->digestlen << 3;
180 OUTPUT:
181 	RETVAL
182 
183 void
184 add(self, ...)
185 	SV *	self
186 PREINIT:
187 	int i;
188 	UCHR *data;
189 	STRLEN len;
190 	SHA3 *state;
191 PPCODE:
192 	if ((state = getSHA3(aTHX_ self)) == NULL)
193 		XSRETURN_UNDEF;
194 	for (i = 1; i < items; i++) {
195 		data = (UCHR *) (SvPVbyte(ST(i), len));
196 		while (len > MAX_WRITE_SIZE) {
197 			shawrite(data, MAX_WRITE_SIZE << 3, state);
198 			data += MAX_WRITE_SIZE;
199 			len  -= MAX_WRITE_SIZE;
200 		}
201 		shawrite(data, (ULNG) len << 3, state);
202 	}
203 	XSRETURN(1);
204 
205 SV *
206 digest(self)
207 	SV *	self
208 ALIAS:
209 	Digest::SHA3::digest = 0
210 	Digest::SHA3::hexdigest = 1
211 	Digest::SHA3::b64digest = 2
212 	Digest::SHA3::squeeze = 3
213 PREINIT:
214 	STRLEN len;
215 	SHA3 *state;
216 	char *result;
217 CODE:
218 	if ((state = getSHA3(aTHX_ self)) == NULL)
219 		XSRETURN_UNDEF;
220 	shafinish(state);
221 	len = 0;
222 	if (ix == 0) {
223 		result = (char *) shadigest(state);
224 		len = (STRLEN) state->digestlen;
225 	}
226 	else if (ix == 1)
227 		result = shahex(state);
228 	else if (ix == 2)
229 		result = shabase64(state);
230 	else {
231 		if ((result = (char *) shasqueeze(state)) == NULL)
232 			XSRETURN_UNDEF;
233 		len = (STRLEN) state->digestlen;
234 	}
235 	RETVAL = newSVpv(result, len);
236 	if (ix != 3)
237 		sharewind(state);
238 OUTPUT:
239 	RETVAL
240 
241 void
242 _addfilebin(self, f)
243 	SV *		self
244 	PerlIO *	f
245 PREINIT:
246 	SHA3 *state;
247 	int n;
248 	UCHR in[IO_BUFFER_SIZE];
249 PPCODE:
250 	if (!f || (state = getSHA3(aTHX_ self)) == NULL)
251 		XSRETURN_UNDEF;
252 	while ((n = (int) PerlIO_read(f, in, sizeof(in))) > 0)
253 		shawrite(in, (ULNG) n << 3, state);
254 	XSRETURN(1);
255 
256 void
257 _addfileuniv(self, f)
258 	SV *		self
259 	PerlIO *	f
260 PREINIT:
261 	UCHR c;
262 	int n;
263 	int cr = 0;
264 	UCHR *src, *dst;
265 	UCHR in[IO_BUFFER_SIZE+1];
266 	SHA3 *state;
267 PPCODE:
268 	if (!f || (state = getSHA3(aTHX_ self)) == NULL)
269 		XSRETURN_UNDEF;
270 	while ((n = (int) PerlIO_read(f, in+1, IO_BUFFER_SIZE)) > 0) {
271 		for (dst = in, src = in + 1; n; n--) {
272 			c = *src++;
273 			if (!cr) {
274 				if (c == '\015')
275 					cr = 1;
276 				else
277 					*dst++ = c;
278 			}
279 			else {
280 				if (c == '\015')
281 					*dst++ = '\012';
282 				else if (c == '\012') {
283 					*dst++ = '\012';
284 					cr = 0;
285 				}
286 				else {
287 					*dst++ = '\012';
288 					*dst++ = c;
289 					cr = 0;
290 				}
291 			}
292 		}
293 		shawrite(in, (ULNG) (dst - in) << 3, state);
294 	}
295 	if (cr) {
296 		in[0] = '\012';
297 		shawrite(in, 1UL << 3, state);
298 	}
299 	XSRETURN(1);
300