/ c_src / sha3_nif.c
sha3_nif.c
  1  #include "erl_nif.h"
  2  #include "KeccakNISTInterface.h"
  3  
  4  typedef struct nif_hash_context     nif_hash_context;
  5  
  6  struct nif_hash_context {
  7    int bitlen;
  8    hashState state;
  9  };
 10  
 11  static void sha3_resource_cleanup(ErlNifEnv* env, void* arg);
 12  static ERL_NIF_TERM nif_hash_init(ErlNifEnv* env, int argc,
 13      const ERL_NIF_TERM argv[]);
 14  static ERL_NIF_TERM nif_hash_update(ErlNifEnv* env, int argc,
 15      const ERL_NIF_TERM argv[]);
 16  static ERL_NIF_TERM nif_hash_final(ErlNifEnv* env, int argc,
 17      const ERL_NIF_TERM argv[]);
 18  static ERL_NIF_TERM nif_hash(ErlNifEnv* env, int argc,
 19      const ERL_NIF_TERM argv[]);
 20  
 21  static ErlNifFunc nif_funcs[] =
 22  {
 23    {"hash_init", 1, nif_hash_init},
 24    {"hash_update", 2, nif_hash_update},
 25    {"hash_final", 1, nif_hash_final},
 26    {"hash", 2, nif_hash}
 27  };
 28  
 29  static ErlNifResourceType *sha3_resource_type;
 30  
 31  static void
 32  sha3_resource_cleanup(ErlNifEnv* env, void* arg)
 33  {
 34    /* do nothing */
 35  }
 36  
 37  static ERL_NIF_TERM
 38  nif_hash_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
 39  {
 40    ERL_NIF_TERM ctxt_term;
 41    nif_hash_context *ctxt;
 42    int bitlen;
 43  
 44    if (!enif_get_int(env, argv[0], &bitlen))
 45      return 0;
 46  
 47    if (bitlen != 224 && bitlen != 256 && bitlen != 384 && bitlen != 512)
 48      return 0;
 49  
 50    ctxt = enif_alloc_resource(sha3_resource_type, sizeof(nif_hash_context));
 51    ctxt->bitlen = bitlen;
 52    Init(&ctxt->state, bitlen);
 53    ctxt_term = enif_make_resource(env, ctxt);
 54    enif_release_resource(ctxt);
 55  
 56    return ctxt_term;
 57  }
 58  
 59  static ERL_NIF_TERM
 60  nif_hash_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
 61  {
 62    ERL_NIF_TERM ctxt_term;
 63    ErlNifBinary src_bin;
 64    nif_hash_context *ctxt, *new;
 65    hashState state;
 66  
 67    if (!enif_get_resource(env, argv[0], sha3_resource_type, (void **)&ctxt) ||
 68        !enif_inspect_binary(env, argv[1], &src_bin))
 69      return 0;
 70  
 71    state = ctxt->state;
 72    Update(&state, src_bin.data, src_bin.size * 8);
 73    new = enif_alloc_resource(sha3_resource_type, sizeof(nif_hash_context));
 74    new->bitlen = ctxt->bitlen;
 75    new->state = state;
 76    ctxt_term = enif_make_resource(env, new);
 77    enif_release_resource(new);
 78  
 79    return ctxt_term;
 80  }
 81  
 82  static ERL_NIF_TERM
 83  nif_hash_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
 84  {
 85    ERL_NIF_TERM digest_term;
 86    ErlNifBinary digest_bin;
 87    nif_hash_context *ctxt;
 88    hashState state;
 89  
 90    if (!enif_get_resource(env, argv[0], sha3_resource_type, (void **)&ctxt))
 91      return 0;
 92  
 93    state = ctxt->state;
 94    enif_alloc_binary(ctxt->bitlen / 8, &digest_bin);
 95    Final(&state, digest_bin.data);
 96    digest_term = enif_make_binary(env, &digest_bin);
 97    enif_release_binary(&digest_bin);
 98  
 99    return digest_term;
100  }
101  
102  static ERL_NIF_TERM
103  nif_hash(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
104  {
105    ERL_NIF_TERM digest_term;
106    ErlNifBinary src_bin, digest_bin;
107    int bitlen;
108  
109    if (!enif_get_int(env, argv[0], &bitlen) ||
110        !enif_inspect_binary(env, argv[1], &src_bin))
111      return 0;
112  
113    if (bitlen != 224 && bitlen != 256 && bitlen != 384 && bitlen != 512)
114      return 0;
115  
116    enif_alloc_binary(bitlen / 8, &digest_bin);
117    Hash(bitlen, src_bin.data, src_bin.size * 8, digest_bin.data);
118    digest_term = enif_make_binary(env, &digest_bin);
119    enif_release_binary(&digest_bin);
120  
121    return digest_term;
122  }
123  
124  static int
125  on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
126  {
127    ErlNifResourceFlags flags = ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER;
128  
129    sha3_resource_type = enif_open_resource_type(env, NULL, "sha3_resource",
130        &sha3_resource_cleanup, flags, NULL);
131    if (sha3_resource_type == NULL)
132      return -1;
133    else
134      return 0;
135  }
136  
137  static void
138  on_unload(ErlNifEnv* env, void* priv_data)
139  {
140    /* do nothing */
141  }
142  
143  ERL_NIF_INIT(sha3, nif_funcs, &on_load, NULL, NULL, &on_unload);
144