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