/* vim: set expandtab ts=4 sw=4 nowrap ft=xs ff=unix : */
#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
#undef ALIGN
#undef LIKELY
#include "../blake2/sse/blake2x.c"
#include "modp_b16.h"
#include "modp_b64.h"
#include "modp_b64w.h"
#include "modp_b85.h"
#define BLAKE2x
enum encode_type {
encode_type_raw,
encode_type_hex,
encode_type_base64,
encode_type_base64url,
encode_type_ascii85
};
inline static SV *
encode_string(pTHX_ const char *src, enum encode_type type) {
int encoded_len;
switch (type) {
case encode_type_raw:
default:
return sv_2mortal(newSVpv(src, BLAKE2x_OUTBYTES));
break;
case encode_type_hex:
{
char buffer[modp_b16_encode_len(BLAKE2x_OUTBYTES)];
encoded_len = modp_b16_encode(buffer, src, BLAKE2x_OUTBYTES);
return sv_2mortal(newSVpv(buffer, encoded_len));
}
break;
case encode_type_base64:
{
char buffer[modp_b64_encode_len(BLAKE2x_OUTBYTES)];
encoded_len = modp_b64_encode(buffer, src, BLAKE2x_OUTBYTES);
#if (defined BLAKE2s) || (defined BLAKE2sp)
/* remove trailing padding 1 characters */
return sv_2mortal(newSVpv(buffer, encoded_len - 1));
#elif (defined BLAKE2b) || (defined BLAKE2bp)
/* remove trailing padding 2 characters */
return sv_2mortal(newSVpv(buffer, encoded_len - 2));
#endif
}
break;
case encode_type_base64url:
{
char buffer[modp_b64w_encode_len(BLAKE2x_OUTBYTES)];
encoded_len = modp_b64w_encode(buffer, src, BLAKE2x_OUTBYTES);
#if (defined BLAKE2s) || (defined BLAKE2sp)
/* remove trailing padding 1 characters */
return sv_2mortal(newSVpv(buffer, encoded_len - 1));
#elif (defined BLAKE2b) || (defined BLAKE2bp)
/* remove trailing padding 2 characters */
return sv_2mortal(newSVpv(buffer, encoded_len - 2));
#endif
}
break;
case encode_type_ascii85:
{
char buffer[modp_b85_encode_len(BLAKE2x_OUTBYTES)];
encoded_len = modp_b85_encode(buffer, src, BLAKE2x_OUTBYTES);
return sv_2mortal(newSVpv(buffer, encoded_len));
}
break;
}
}
typedef blake2x_state *Digest__BLAKE2x;
MODULE = Digest::BLAKE2x PACKAGE = Digest::BLAKE2x
Digest::BLAKE2x
new (class)
SV *class
CODE:
Newx(RETVAL, 1, blake2x_state);
if (blake2x_init(RETVAL, BLAKE2x_OUTBYTES)) {
XSRETURN_UNDEF;
}
OUTPUT:
RETVAL
Digest::BLAKE2x
clone (self)
Digest::BLAKE2x self
CODE:
Newx(RETVAL, 1, blake2x_state);
Copy(self, RETVAL, 1, blake2x_state);
OUTPUT:
RETVAL
void
add (self, ...)
Digest::BLAKE2x self
PREINIT:
int i;
uint8_t *in;
STRLEN inlen;
PPCODE:
for (i = 1; i < items; i++) {
in = (uint8_t *)(SvPV(ST(i), inlen));
blake2x_update(self, in, inlen);
}
XSRETURN(1);
void
digest (self)
Digest::BLAKE2x self
PREINIT:
uint8_t out[BLAKE2x_OUTBYTES];
CODE:
blake2x_final(self, out, BLAKE2x_OUTBYTES);
ST(0) = sv_2mortal(newSVpv((const char *)out, BLAKE2x_OUTBYTES));
XSRETURN(1);
void
DESTROY (self)
Digest::BLAKE2x self
CODE:
Safefree(self);
void
blake2x (...)
ALIAS:
blake2x = encode_type_raw
blake2x_hex = encode_type_hex
blake2x_base64 = encode_type_base64
blake2x_base64url = encode_type_base64url
blake2x_ascii85 = encode_type_ascii85
PREINIT:
int i;
uint8_t *in;
STRLEN inlen;
blake2x_state *state;
uint8_t out[BLAKE2x_OUTBYTES];
CODE:
Newx(state, 1, blake2x_state);
if (blake2x_init(state, BLAKE2x_OUTBYTES)) {
XSRETURN_UNDEF;
}
for (i = 0; i < items; i++) {
in = (uint8_t *)(SvPV(ST(i), inlen));
blake2x_update(state, in, inlen);
}
blake2x_final(state, out, BLAKE2x_OUTBYTES);
Safefree(state);
ST(0) = encode_string(aTHX_ (char *)out, ix);
XSRETURN(1);