Packages

A post-quantum cryptography library for digital signatures based on the Falcon algorithm

Current section

Files

Jump to
ex_falcon c_src falcon_nif.c
Raw

c_src/falcon_nif.c

#include "inner.h"
#include "falcon.h"
#include "tools.c"
#include <stdio.h>
#include <string.h>
#include "erl_nif.h"
// #define FALSE 0
// #define TRUE 1
#define CRYPTO_LOGN (unsigned)9 // falcon-512 = 9 | falcon-1024 = 10
#define PUBKEY_LEN FALCON_PUBKEY_SIZE(CRYPTO_LOGN)
#define PRIVKEY_LEN FALCON_PRIVKEY_SIZE(CRYPTO_LOGN)
#define SIGN_TYPE FALCON_SIG_COMPRESSED
#define SIGN_LEN FALCON_SIG_COMPRESSED_MAXSIZE(CRYPTO_LOGN)
#define SIGN_MAX_LEN FALCON_SIG_PADDED_SIZE(CRYPTO_LOGN)
#define SIGN_START_SIZE 41
// #define EXPKEY_LEN FALCON_EXPANDEDKEY_SIZE(CRYPTO_LOGN)
const uint8_t START[] = {57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static ERL_NIF_TERM
gen_key_pair(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary pub_bin, priv_bin;
if (argc != 0)
return enif_make_badarg(env);
void *pubkey, *privkey;
uint8_t *tmpkg;
shake256_context rng;
size_t tmpkg_len, pubkey_len, privkey_len;
tmpkg_len = FALCON_TMPSIZE_KEYGEN(CRYPTO_LOGN);
pubkey_len = FALCON_PUBKEY_SIZE(CRYPTO_LOGN);
privkey_len = FALCON_PRIVKEY_SIZE(CRYPTO_LOGN);
pubkey = xmalloc(pubkey_len);
privkey = xmalloc(privkey_len);
tmpkg = xmalloc(tmpkg_len);
memset(pubkey, 0, pubkey_len);
memset(privkey, 0, privkey_len);
shake256_init_prng_from_system(&rng);
int r = falcon_keygen_make(&rng, CRYPTO_LOGN, privkey, privkey_len, pubkey, pubkey_len, tmpkg, tmpkg_len);
if (r != 0)
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "keygen_fail"));
if (enif_alloc_binary(pubkey_len, &pub_bin))
{
memcpy(pub_bin.data, pubkey, pub_bin.size);
if (enif_alloc_binary(privkey_len, &priv_bin))
{
memcpy(priv_bin.data, privkey, privkey_len);
xfree(pubkey);
xfree(privkey);
xfree(tmpkg);
return enif_make_tuple3(
env,
enif_make_atom(env, "ok"),
enif_make_binary(env, &pub_bin),
enif_make_binary(env, &priv_bin));
}
}
xfree(pubkey);
xfree(privkey);
xfree(tmpkg);
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "mem_alloc"));
}
static ERL_NIF_TERM
gen_pub_key(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary pub_bin, priv_bin;
if (argc != 1 || !enif_inspect_binary(env, argv[0], &priv_bin))
return enif_make_badarg(env);
if (priv_bin.size != PRIVKEY_LEN)
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "key_size"));
void *pubkey;
uint8_t *tmpmp;
size_t pubkey_len, tmpmp_len, privkey_len;
pubkey_len = FALCON_PUBKEY_SIZE(CRYPTO_LOGN);
privkey_len = FALCON_PRIVKEY_SIZE(CRYPTO_LOGN);
tmpmp_len = FALCON_TMPSIZE_MAKEPUB(CRYPTO_LOGN);
pubkey = xmalloc(pubkey_len);
tmpmp = xmalloc(tmpmp_len);
memset(pubkey, 0, PUBKEY_LEN);
int r = falcon_make_public(pubkey, PUBKEY_LEN,
priv_bin.data, PRIVKEY_LEN, tmpmp, tmpmp_len);
if (r != 0)
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "makepub_fail"));
if (enif_alloc_binary(PUBKEY_LEN, &pub_bin))
{
memcpy(pub_bin.data, pubkey, PUBKEY_LEN);
xfree(pubkey);
xfree(tmpmp);
return enif_make_tuple2(
env,
enif_make_atom(env, "ok"),
enif_make_binary(env, &pub_bin));
}
xfree(pubkey);
xfree(tmpmp);
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "mem_alloc"));
}
static ERL_NIF_TERM
gen_keys_from_seed(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary seed_bin, pub_bin, priv_bin;
if (argc != 1 || !enif_inspect_binary(env, argv[0], &seed_bin))
{
return enif_make_badarg(env);
}
void *pubkey, *privkey;
uint8_t *tmpkg;
size_t tmpkg_len;
shake256_context rng;
tmpkg_len = FALCON_TMPSIZE_KEYGEN(CRYPTO_LOGN);
pubkey = xmalloc(PUBKEY_LEN);
privkey = xmalloc(PRIVKEY_LEN);
tmpkg = xmalloc(tmpkg_len);
memset(privkey, 0, PRIVKEY_LEN);
memset(pubkey, 0, PUBKEY_LEN);
shake256_init_prng_from_seed(&rng, seed_bin.data, seed_bin.size);
int r = falcon_keygen_make(&rng, CRYPTO_LOGN, privkey, PRIVKEY_LEN, pubkey, PUBKEY_LEN, tmpkg, tmpkg_len);
if (r != 0)
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "keygen_fail"));
if (enif_alloc_binary(PUBKEY_LEN, &pub_bin))
{
memcpy(pub_bin.data, pubkey, PUBKEY_LEN);
if (enif_alloc_binary(PRIVKEY_LEN, &priv_bin))
{
memcpy(priv_bin.data, privkey, PRIVKEY_LEN);
xfree(pubkey);
xfree(privkey);
xfree(tmpkg);
return enif_make_tuple3(
env,
enif_make_atom(env, "ok"),
enif_make_binary(env, &pub_bin),
enif_make_binary(env, &priv_bin));
}
}
}
static ERL_NIF_TERM
sign(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary priv_bin, msg_bin, sig_bin;
if (argc != 2 ||
!enif_inspect_binary(env, argv[0], &priv_bin) ||
!enif_inspect_binary(env, argv[1], &msg_bin))
{
return enif_make_badarg(env);
}
if (priv_bin.size != PRIVKEY_LEN)
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "key_size"));
size_t sig_len, tmpsd_len;
uint8_t *sig;
uint8_t *tmpsd;
shake256_context rng;
sig_len = SIGN_MAX_LEN;
tmpsd_len = FALCON_TMPSIZE_SIGNDYN(CRYPTO_LOGN);
sig = xmalloc(sig_len);
tmpsd = xmalloc(tmpsd_len);
memset(sig, 0, sig_len);
shake256_init_prng_from_system(&rng);
int r = falcon_sign_dyn(&rng, sig, &sig_len, SIGN_TYPE,
priv_bin.data, priv_bin.size,
msg_bin.data, msg_bin.size, tmpsd, tmpsd_len);
if (r != 0)
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "sign_failed"));
//SIGN_MAX_LEN == sig_len ? SIGN_MAX_LEN + 1 : sig_len;
size_t sig_size = sig_len - SIGN_START_SIZE;
if (enif_alloc_binary(sig_size, &sig_bin))
{
memcpy(sig_bin.data, sig + SIGN_START_SIZE, sig_size);
xfree(tmpsd);
xfree(sig);
return enif_make_tuple2(env, enif_make_atom(env, "ok"), enif_make_binary(env, &sig_bin));
}
xfree(tmpsd);
xfree(sig);
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "mem_alloc"));
}
static ERL_NIF_TERM
verify(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary msg_bin, sig_bin, pub_bin;
if (argc != 3 ||
!enif_inspect_binary(env, argv[0], &msg_bin) ||
!enif_inspect_binary(env, argv[1], &sig_bin) ||
!enif_inspect_binary(env, argv[2], &pub_bin))
{
return enif_make_badarg(env);
}
if (pub_bin.size != PUBKEY_LEN)
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "key_size"));
if (sig_bin.size > SIGN_MAX_LEN)
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "sign_size"));
size_t tmpvv_len = FALCON_TMPSIZE_VERIFY(CRYPTO_LOGN);
uint8_t *tmpvv = xmalloc(tmpvv_len);
// size_t sig_size = sig_bin.size == (SIGN_MAX_LEN + 1) ? (sig_bin.size - 1) : sig_bin.size;
uint8_t *sig;
size_t sig_size = sig_bin.size + SIGN_START_SIZE;
sig = xmalloc(sig_size);
memcpy(sig, &START, SIGN_START_SIZE);
memcpy(sig + SIGN_START_SIZE, sig_bin.data, sig_bin.size);
int r = falcon_verify(sig, sig_size, SIGN_TYPE,
pub_bin.data, pub_bin.size, msg_bin.data, msg_bin.size,
tmpvv, tmpvv_len);
xfree(tmpvv);
xfree(sig);
if (r != 0)
return enif_make_atom(env, "error");
return enif_make_atom(env, "ok");
}
static ErlNifFunc nif_funcs[] = {
{"gen_key_pair", 0, gen_key_pair},
{"gen_pub_key", 1, gen_pub_key},
{"gen_keys_from_seed", 1, gen_keys_from_seed},
{"sign", 2, sign},
{"verify", 3, verify}};
ERL_NIF_INIT(Elixir.Falcon, nif_funcs, NULL, NULL, NULL, NULL)