ecrecover/c_src/ecrecover.c
2023-01-13 11:31:14 +01:00

101 lines
2.4 KiB
C

// Very specific NIF just for key recovery.
// Partly from https://github.com/mbrix/libsecp256k1
#include "erl_nif.h"
#include "secp256k1_recovery.h"
static secp256k1_context *ctx = NULL;
static ERL_NIF_TERM error_result(ErlNifEnv* env, char* error_msg)
{
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_string(env, error_msg, ERL_NIF_LATIN1));
}
static ERL_NIF_TERM ok_result(ErlNifEnv* env, ERL_NIF_TERM *r)
{
return enif_make_tuple2(env, enif_make_atom(env, "ok"), *r);
}
static ERL_NIF_TERM
recover(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ERL_NIF_TERM r;
ErlNifBinary message, csignature;
int result;
int compressed = SECP256K1_EC_UNCOMPRESSED;
size_t pubkeylen = 65;
int recid;
unsigned char* finished_recpubkey_buf;
secp256k1_ecdsa_recoverable_signature signature;
secp256k1_pubkey recpubkey;
if (!enif_inspect_binary(env, argv[0], &message)) {
return enif_make_badarg(env);
}
if (!enif_inspect_binary(env, argv[1], &csignature)) {
return enif_make_badarg(env);
}
if (!enif_get_int(env, argv[2], &recid)) {
return error_result(env, "Recovery id invalid not integer 0-3");
}
if (recid < 0 || recid > 3) {
error_result(env, "Recovery id invalid 0-3");
}
result = secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &signature, csignature.data, recid);
if (!result) {
return error_result(env, "ecdsa_signature_parse_compact returned 0");
}
// Now do ECDSA recovery
result = secp256k1_ecdsa_recover(ctx, &recpubkey, &signature, message.data);
if (!result) {
return error_result(env, "ecdsa recovery problem");
}
// Now serialize recpubkey
finished_recpubkey_buf = enif_make_new_binary(env, pubkeylen, &r);
result = secp256k1_ec_pubkey_serialize(ctx, finished_recpubkey_buf,
&pubkeylen, &recpubkey, compressed);
if (!result) {
return error_result(env, "ecdsa pubkey serialize error");
}
return ok_result(env, &r);
}
static int
load(ErlNifEnv* env, void** priv, ERL_NIF_TERM load_info)
{
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
return 0;
}
static int
upgrade(ErlNifEnv* env, void** priv, void** old_priv, ERL_NIF_TERM load_info)
{
return 0;
}
static void
unload(ErlNifEnv* env, void* priv)
{
secp256k1_context_destroy(ctx);
return;
}
static ErlNifFunc nif_funcs[] =
{
{"recover", 3, recover}
};
ERL_NIF_INIT(ecrecover, nif_funcs, &load, NULL, NULL, &unload);