Packages

libdecaf NIF for ECDH (X25519, X448), EdDSA (Ed25519, Ed25519ctx, Ed25519ph, Ed448, Ed448ph), curve25519, curve448, spongerng

Current section

Files

Jump to
libdecaf c_src sha512_funcs.h
Raw

c_src/sha512_funcs.h

// -*- mode: c; tab-width: 8; indent-tabs-mode: 1; st-rulers: [70] -*-
// vim: ts=8 sw=8 ft=c noet
#include <decaf/sha512.h>
/*
* Erlang NIF functions
*/
static ERL_NIF_TERM
libdecaf_sha2_512_2(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary in;
unsigned long outlen;
if (argc != 2 || !enif_inspect_binary(env, argv[0], &in)
|| !enif_get_ulong(env, argv[1], &outlen)
|| outlen > 64) {
return enif_make_badarg(env);
}
if (in.size <= MAX_PER_SLICE) {
ERL_NIF_TERM out;
unsigned char *buf = enif_make_new_binary(env, outlen, &out);
(void) sha512_hash(buf, outlen, in.data, in.size);
return out;
}
libdecaf_priv_data_t *priv_data = (libdecaf_priv_data_t *)(enif_priv_data(env));
ErlNifResourceType *resource_type = priv_data->sha2_512_ctx;
void *resource = enif_alloc_resource(resource_type, sizeof(sha512_ctx_t));
struct sha512_ctx_s *ctx = (struct sha512_ctx_s *)(resource);
(void) sha512_init(ctx);
ERL_NIF_TERM newargv[5];
newargv[0] = argv[0]; /* In */
newargv[1] = argv[1]; /* Outlen */
newargv[2] = enif_make_ulong(env, MAX_PER_SLICE); /* MaxPerSlice */
newargv[3] = enif_make_ulong(env, 0); /* Offset */
newargv[4] = enif_make_resource(env, resource); /* Context */
(void) enif_release_resource(resource);
return enif_schedule_nif(env, "sha2_512", 0, libdecaf_sha2_512_5, 5, newargv);
}
static ERL_NIF_TERM
libdecaf_sha2_512_5(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary in;
unsigned long outlen;
unsigned long max_per_slice;
unsigned long offset;
libdecaf_priv_data_t *priv_data = (libdecaf_priv_data_t *)(enif_priv_data(env));
ErlNifResourceType *resource_type = priv_data->sha2_512_ctx;
void *resource;
if (argc != 5 || !enif_inspect_binary(env, argv[0], &in)
|| !enif_get_ulong(env, argv[1], &outlen)
|| !enif_get_ulong(env, argv[2], &max_per_slice)
|| !enif_get_ulong(env, argv[3], &offset)
|| !enif_get_resource(env, argv[4], resource_type, &resource)) {
return enif_make_badarg(env);
}
struct sha512_ctx_s *ctx = (struct sha512_ctx_s *)(resource);
struct timeval start;
struct timeval stop;
struct timeval slice;
unsigned long end;
unsigned long i;
int percent;
int total = 0;
end = offset + max_per_slice;
if (end > in.size) {
end = in.size;
}
i = offset;
while (i < in.size) {
(void) gettimeofday(&start, NULL);
(void) sha512_update(ctx, (uint8_t *)(in.data) + i, end - i);
i = end;
if (i == in.size) {
break;
}
(void) gettimeofday(&stop, NULL);
/* determine how much of the timeslice was used */
timersub(&stop, &start, &slice);
percent = (int)((slice.tv_sec*1000000+slice.tv_usec)/10);
total += percent;
if (percent > 100) {
percent = 100;
} else if (percent == 0) {
percent = 1;
}
if (enif_consume_timeslice(env, percent)) {
/* the timeslice has been used up, so adjust our max_per_slice byte count based on the processing we've done, then reschedule to run again */
max_per_slice = i - offset;
if (total > 100) {
int m = (int)(total/100);
if (m == 1) {
max_per_slice -= (unsigned long)(max_per_slice*(total-100)/100);
} else {
max_per_slice = (unsigned long)(max_per_slice/m);
}
}
ERL_NIF_TERM newargv[5];
newargv[0] = argv[0]; /* In */
newargv[1] = argv[1]; /* Outlen */
newargv[2] = enif_make_ulong(env, max_per_slice); /* MaxPerSlice */
newargv[3] = enif_make_ulong(env, i); /* Offset */
newargv[4] = argv[4]; /* Context */
return enif_schedule_nif(env, "sha2_512", 0, libdecaf_sha2_512_5, argc, newargv);
}
end += max_per_slice;
if (end > in.size) {
end = in.size;
}
}
ERL_NIF_TERM out;
unsigned char *buf = enif_make_new_binary(env, outlen, &out);
(void) sha512_final(ctx, buf, outlen);
(void) sha512_destroy(ctx);
return out;
}
static ERL_NIF_TERM
libdecaf_sha2_512_init_0(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
if (argc != 0) {
return enif_make_badarg(env);
}
ERL_NIF_TERM out;
unsigned char *buf = enif_make_new_binary(env, sizeof(sha512_ctx_t), &out);
struct sha512_ctx_s *ctx = (struct sha512_ctx_s *)(buf);
(void) sha512_init(ctx);
return enif_make_tuple2(env, ATOM_sha2_512, out);
}
static ERL_NIF_TERM
libdecaf_sha2_512_update_2(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
int arity;
const ERL_NIF_TERM *state;
ErlNifBinary state_bin;
ErlNifBinary in;
if (argc != 2 || !enif_get_tuple(env, argv[0], &arity, &state)
|| arity != 2
|| state[0] != ATOM_sha2_512
|| !enif_inspect_binary(env, state[1], &state_bin)
|| state_bin.size != sizeof(sha512_ctx_t)
|| !enif_inspect_binary(env, argv[1], &in)) {
return enif_make_badarg(env);
}
if (in.size <= MAX_PER_SLICE) {
ERL_NIF_TERM out;
unsigned char *buf = enif_make_new_binary(env, state_bin.size, &out);
(void) memcpy(buf, state_bin.data, state_bin.size);
struct sha512_ctx_s *ctx = (struct sha512_ctx_s *)(buf);
(void) sha512_update(ctx, in.data, in.size);
return enif_make_tuple2(env, ATOM_sha2_512, out);
}
libdecaf_priv_data_t *priv_data = (libdecaf_priv_data_t *)(enif_priv_data(env));
ErlNifResourceType *resource_type = priv_data->sha2_512_ctx;
void *resource = enif_alloc_resource(resource_type, state_bin.size);
(void) memcpy(resource, state_bin.data, state_bin.size);
ERL_NIF_TERM newargv[4];
newargv[0] = argv[1]; /* In */
newargv[1] = enif_make_ulong(env, MAX_PER_SLICE); /* MaxPerSlice */
newargv[2] = enif_make_ulong(env, 0); /* Offset */
newargv[3] = enif_make_resource(env, resource); /* Context */
(void) enif_release_resource(resource);
return enif_schedule_nif(env, "sha2_512_update", 0, libdecaf_sha2_512_update_4, 4, newargv);
}
static ERL_NIF_TERM
libdecaf_sha2_512_update_4(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary in;
unsigned long max_per_slice;
unsigned long offset;
libdecaf_priv_data_t *priv_data = (libdecaf_priv_data_t *)(enif_priv_data(env));
ErlNifResourceType *resource_type = priv_data->sha2_512_ctx;
void *resource;
if (argc != 4 || !enif_inspect_binary(env, argv[0], &in)
|| !enif_get_ulong(env, argv[1], &max_per_slice)
|| !enif_get_ulong(env, argv[2], &offset)
|| !enif_get_resource(env, argv[3], resource_type, &resource)) {
return enif_make_badarg(env);
}
struct sha512_ctx_s *ctx = (struct sha512_ctx_s *)(resource);
struct timeval start;
struct timeval stop;
struct timeval slice;
unsigned long end;
unsigned long i;
int percent;
int total = 0;
end = offset + max_per_slice;
if (end > in.size) {
end = in.size;
}
i = offset;
while (i < in.size) {
(void) gettimeofday(&start, NULL);
(void) sha512_update(ctx, (uint8_t *)(in.data) + i, end - i);
i = end;
if (i == in.size) {
break;
}
(void) gettimeofday(&stop, NULL);
/* determine how much of the timeslice was used */
timersub(&stop, &start, &slice);
percent = (int)((slice.tv_sec*1000000+slice.tv_usec)/10);
total += percent;
if (percent > 100) {
percent = 100;
} else if (percent == 0) {
percent = 1;
}
if (enif_consume_timeslice(env, percent)) {
/* the timeslice has been used up, so adjust our max_per_slice byte count based on the processing we've done, then reschedule to run again */
max_per_slice = i - offset;
if (total > 100) {
int m = (int)(total/100);
if (m == 1) {
max_per_slice -= (unsigned long)(max_per_slice*(total-100)/100);
} else {
max_per_slice = (unsigned long)(max_per_slice/m);
}
}
ERL_NIF_TERM newargv[4];
newargv[0] = argv[0]; /* In */
newargv[1] = enif_make_ulong(env, max_per_slice); /* MaxPerSlice */
newargv[2] = enif_make_ulong(env, i); /* Offset */
newargv[3] = argv[3]; /* Context */
return enif_schedule_nif(env, "sha2_512_update", 0, libdecaf_sha2_512_update_4, argc, newargv);
}
end += max_per_slice;
if (end > in.size) {
end = in.size;
}
}
ERL_NIF_TERM out;
unsigned char *buf = enif_make_new_binary(env, sizeof(sha512_ctx_t), &out);
(void) memcpy(buf, resource, sizeof(sha512_ctx_t));
return enif_make_tuple2(env, ATOM_sha2_512, out);
}
static ERL_NIF_TERM
libdecaf_sha2_512_final_2(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
int arity;
const ERL_NIF_TERM *state;
ErlNifBinary state_bin;
unsigned long outlen;
if (argc != 2 || !enif_get_tuple(env, argv[0], &arity, &state)
|| arity != 2
|| state[0] != ATOM_sha2_512
|| !enif_inspect_binary(env, state[1], &state_bin)
|| state_bin.size != sizeof(sha512_ctx_t)
|| !enif_get_ulong(env, argv[1], &outlen)
|| outlen > 64) {
return enif_make_badarg(env);
}
libdecaf_priv_data_t *priv_data = (libdecaf_priv_data_t *)(enif_priv_data(env));
ErlNifResourceType *resource_type = priv_data->sha2_512_ctx;
void *resource = enif_alloc_resource(resource_type, state_bin.size);
(void) memcpy(resource, state_bin.data, state_bin.size);
struct sha512_ctx_s *ctx = (struct sha512_ctx_s *)(resource);
ERL_NIF_TERM out;
unsigned char *buf = enif_make_new_binary(env, outlen, &out);
(void) sha512_final(ctx, buf, outlen);
(void) sha512_destroy(ctx);
(void) enif_release_resource(resource);
return out;
}