From 868a14c25da4b5fcf0a1f4783202ad7800fe4682 Mon Sep 17 00:00:00 2001 From: Bryan Paxton Date: Sun, 26 Jul 2020 14:25:24 -0500 Subject: [PATCH 1/6] Ensure we never return 1 from sodium_init() onload sodium_init() will return 0 on success, -1 on failure, and 1 if sodium is already loaded and initialized (which is not an error). In the case where libsodium is already initialized and the system is restarted we may return 1 from onload nif function resulting in a crash. - change the call to sodium_init() to check for an error return (-1) and return -1 explicitly in this case, otherwise always return zero at the end of our onload function. --- c_src/enacl_nif.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/c_src/enacl_nif.c b/c_src/enacl_nif.c index 2af0b0a..db34ab8 100644 --- a/c_src/enacl_nif.c +++ b/c_src/enacl_nif.c @@ -36,7 +36,11 @@ int enif_crypto_load(ErlNifEnv *env, void **priv_data, ERL_NIF_TERM load_info) { return -1; } - return sodium_init(); + if (sodium_init() == -1) { + return -1; + } + + return 0; } /* Low-level functions (Hashing, String Equality, ...) */ From 80e24670d9a026e04ea0010a04d91885e88b6abf Mon Sep 17 00:00:00 2001 From: Sean Hinde Date: Tue, 16 Nov 2021 15:08:23 +0100 Subject: [PATCH 2/6] on Darwin allow platform to decide arch --- rebar.config | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rebar.config b/rebar.config index e9d0ca5..988a056 100644 --- a/rebar.config +++ b/rebar.config @@ -18,9 +18,9 @@ ]}. {port_env, [ - {"darwin", "CFLAGS", "$CFLAGS -fPIC -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes"}, - {"darwin", "CXXFLAGS", "$CXXFLAGS -fPIC -O3 -arch x86_64 -finline-functions -Wall"}, - {"darwin", "LDFLAGS", "$LDFLAGS -arch x86_64 -flat_namespace -undefined suppress -lsodium"}, + {"darwin", "CFLAGS", "$CFLAGS -fPIC -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes"}, + {"darwin", "CXXFLAGS", "$CXXFLAGS -fPIC -O3 -finline-functions -Wall"}, + {"darwin", "LDFLAGS", "$LDFLAGS -flat_namespace -undefined suppress -lsodium"}, {"linux", "CFLAGS", "$CFLAGS -fPIC -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes"}, {"linux", "CXXFLAGS", "$CXXFLAGS -fPIC -O3 -finline-functions -Wall"}, From fa94eaf6f622392eb6021c36cbb1bc024af0128c Mon Sep 17 00:00:00 2001 From: Hans Svensson Date: Thu, 6 Jan 2022 18:26:21 +0100 Subject: [PATCH 3/6] Add access to secretbox_easy/easy_open functions They are just a simplification of the secretbox API, thus it does not provide any new functionality. But it helps mapping function names to libsodium documentation. --- c_src/enacl_nif.c | 6 +++++ c_src/secret.c | 58 ++++++++++++++++++++++++++++++++++++++++++ c_src/secret.h | 6 +++++ eqc_test/enacl_eqc.erl | 38 +++++++++++++++++++++++++++ src/enacl.erl | 46 +++++++++++++++++++++++++++++++++ src/enacl_nif.erl | 8 ++++++ 6 files changed, 162 insertions(+) diff --git a/c_src/enacl_nif.c b/c_src/enacl_nif.c index 268096a..5f67ab4 100644 --- a/c_src/enacl_nif.c +++ b/c_src/enacl_nif.c @@ -256,6 +256,12 @@ static ErlNifFunc nif_funcs[] = { {"crypto_secretbox_open_b", 3, enacl_crypto_secretbox_open}, erl_nif_dirty_job_cpu_bound_macro("crypto_secretbox_open", 3, enacl_crypto_secretbox_open), + {"crypto_secretbox_easy_b", 3, enacl_crypto_secretbox_easy}, + erl_nif_dirty_job_cpu_bound_macro("crypto_secretbox_easy", 3, + enacl_crypto_secretbox_easy), + {"crypto_secretbox_open_easy_b", 3, enacl_crypto_secretbox_open_easy}, + erl_nif_dirty_job_cpu_bound_macro("crypto_secretbox_open_easy", 3, + enacl_crypto_secretbox_open_easy), {"crypto_stream_chacha20_KEYBYTES", 0, enacl_crypto_stream_chacha20_KEYBYTES}, diff --git a/c_src/secret.c b/c_src/secret.c index 627d444..8a681a4 100644 --- a/c_src/secret.c +++ b/c_src/secret.c @@ -137,6 +137,64 @@ ERL_NIF_TERM enacl_crypto_secretbox_open(ErlNifEnv *env, int argc, return enif_make_tuple2(env, ret_ok, ret_bin); } +ERL_NIF_TERM enacl_crypto_secretbox_easy(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary key, nonce, msg, cipherbox; + + if ((argc != 3) || + (!enif_inspect_iolist_as_binary(env, argv[0], &msg)) || + (!enif_inspect_binary(env, argv[1], &nonce)) || + (!enif_inspect_binary(env, argv[2], &key))) { + return enif_make_badarg(env); + } + + if ((key.size != crypto_secretbox_KEYBYTES) || + (nonce.size != crypto_secretbox_NONCEBYTES)) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(msg.size + crypto_secretbox_MACBYTES, &cipherbox)) { + return enacl_internal_error(env); + } + + crypto_secretbox_easy(cipherbox.data, msg.data, msg.size, + nonce.data, key.data); + + return enif_make_binary(env, &cipherbox); +} + +ERL_NIF_TERM enacl_crypto_secretbox_open_easy(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary key, nonce, cipherbox, msg; + + if ((argc != 3) || + (!enif_inspect_iolist_as_binary(env, argv[0], &cipherbox)) || + (!enif_inspect_binary(env, argv[1], &nonce)) || + (!enif_inspect_binary(env, argv[2], &key))) { + return enif_make_badarg(env); + } + + if ((key.size != crypto_secretbox_KEYBYTES) || + (nonce.size != crypto_secretbox_NONCEBYTES) || + (cipherbox.size < crypto_secretbox_MACBYTES)) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(cipherbox.size - crypto_secretbox_MACBYTES, &msg)) { + return enacl_internal_error(env); + } + + if (crypto_secretbox_open_easy(msg.data, cipherbox.data, cipherbox.size, + nonce.data, key.data) != 0) { + enif_release_binary(&msg); + return enacl_error_tuple(env, "failed_verification"); + } + + ERL_NIF_TERM ret_ok = enif_make_atom(env, ATOM_OK); + ERL_NIF_TERM ret_bin = enif_make_binary(env, &msg); + return enif_make_tuple2(env, ret_ok, ret_bin); +} + ERL_NIF_TERM enacl_crypto_stream_chacha20(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) { ErlNifBinary c, n, k; diff --git a/c_src/secret.h b/c_src/secret.h index 6c0a4c8..569c7a5 100644 --- a/c_src/secret.h +++ b/c_src/secret.h @@ -43,6 +43,12 @@ ERL_NIF_TERM enacl_crypto_secretbox(ErlNifEnv *env, int argc, ERL_NIF_TERM enacl_crypto_secretbox_open(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]); +ERL_NIF_TERM enacl_crypto_secretbox_easy(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_secretbox_open_easy(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + ERL_NIF_TERM enacl_crypto_stream_chacha20(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]); diff --git a/eqc_test/enacl_eqc.erl b/eqc_test/enacl_eqc.erl index 6093a5b..cec95e6 100644 --- a/eqc_test/enacl_eqc.erl +++ b/eqc_test/enacl_eqc.erl @@ -550,6 +550,44 @@ prop_secretbox_failure_integrity() -> equals(Err, {error, failed_verification}) end). +secretbox_easy(Msg, Nonce, Key) -> + try enacl:secretbox_easy(Msg, Nonce, Key) + catch error:badarg -> badarg + end. + +secretbox_open_easy(Msg, Nonce, Key) -> + try enacl:secretbox_open_easy(Msg, Nonce, Key) + catch error:badarg -> badarg + end. + +prop_secretbox_easy_correct() -> + ?FORALL({Msg, Nonce, Key}, + {?FAULT_RATE(1, 40, g_iodata()), + ?FAULT_RATE(1, 40, nonce()), + ?FAULT_RATE(1, 40, secret_key())}, + begin + case v_iodata(Msg) andalso nonce_valid(Nonce) andalso secret_key_valid(Key) of + true -> + CipherText = enacl:secretbox_easy(Msg, Nonce, Key), + {ok, DecodedMsg} = enacl:secretbox_open_easy(CipherText, Nonce, Key), + equals(iolist_to_binary(Msg), DecodedMsg); + false -> + case secretbox_easy(Msg, Nonce, Key) of + badarg -> true; + Res -> + failure(secretbox_open_easy(Res, Nonce, Key)) + end + end + end). + +prop_secretbox_easy_failure_integrity() -> + ?FORALL({Msg, Nonce, Key}, {g_iodata(), nonce(), secret_key()}, + begin + CipherText = enacl:secretbox_easy(Msg, Nonce, Key), + Err = enacl:secretbox_open_easy([<<"x">>, CipherText], Nonce, Key), + equals(Err, {error, failed_verification}) + end). + %% AEAD ChaCha20Poly1305 %% ------------------------------------------------------------ %% * aead_chacha20poly1305_encrypt/4, diff --git a/src/enacl.erl b/src/enacl.erl index 378bb7b..3599c70 100644 --- a/src/enacl.erl +++ b/src/enacl.erl @@ -59,6 +59,8 @@ secretbox_NONCEBYTES/0, secretbox/3, secretbox_open/3, + secretbox_easy/3, + secretbox_open_easy/3, %% No Tests! stream_chacha20_KEYBYTES/0, @@ -837,6 +839,50 @@ secretbox_open(CipherText, Nonce, Key) -> enacl_nif:crypto_secretbox_open([?S_BOXZEROBYTES, CipherText], Nonce, Key) end. +%% @doc secretbox_easy/3 encrypts a message with a key (and nonce) +%% +%% Given a `Msg', a `Nonce' and a `Key' encrypt the message with the Key while taking the +%% nonce into consideration. `easy' refers to not having to take padding, etc. into +%% account. The function returns the Box obtained from the encryption. +%% @end +-spec secretbox_easy(Msg, Nonce, Key) -> Box + when + Msg :: iodata(), + Nonce :: binary(), + Key :: binary(), + Box :: binary(). +secretbox_easy(Msg, Nonce, Key) -> + case iolist_size(Msg) of + K when K =< ?SECRETBOX_SIZE -> + bump(enacl_nif:crypto_secretbox_easy_b(Msg, Nonce, Key), + ?SECRETBOX_REDUCTIONS, + ?SECRETBOX_SIZE, + K); + _ -> + enacl_nif:crypto_secretbox_easy(Msg, Nonce, Key) + end. + +%% @doc secretbox_open_easy/3 opens a sealed box. +%% +%% Given a boxed `CipherText' and given we know the used `Nonce' and `Key' we can open the box +%% to obtain the `Msg' within. `easy' refers to not having to take padding, etc. into +%% account. Returns either `{ok, Msg}' or `{error, failed_verification}'. +%% @end +-spec secretbox_open_easy(CipherText, Nonce, Key) -> {ok, Msg} | {error, failed_verification} + when + CipherText :: iodata(), + Nonce :: binary(), + Key :: binary(), + Msg :: binary(). +secretbox_open_easy(CipherText, Nonce, Key) -> + case iolist_size(CipherText) of + K when K =< ?SECRETBOX_SIZE -> + R = enacl_nif:crypto_secretbox_open_easy_b(CipherText, Nonce, Key), + bump(R, ?SECRETBOX_OPEN_REDUCTIONS, ?SECRETBOX_SIZE, K); + _ -> + enacl_nif:crypto_secretbox_open_easy(CipherText, Nonce, Key) + end. + %% @doc secretbox_NONCEBYTES()/0 returns the size of the secretbox nonce %% %% When encrypting with a secretbox, the nonce must have this size diff --git a/src/enacl_nif.erl b/src/enacl_nif.erl index 3ecb962..4630202 100644 --- a/src/enacl_nif.erl +++ b/src/enacl_nif.erl @@ -57,6 +57,10 @@ crypto_secretbox_b/3, crypto_secretbox_open/3, crypto_secretbox_open_b/3, + crypto_secretbox_easy/3, + crypto_secretbox_easy_b/3, + crypto_secretbox_open_easy/3, + crypto_secretbox_open_easy_b/3, crypto_stream_chacha20_KEYBYTES/0, crypto_stream_chacha20_NONCEBYTES/0, @@ -303,6 +307,10 @@ crypto_secretbox(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded). crypto_secretbox_b(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded). crypto_secretbox_open(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded). crypto_secretbox_open_b(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded). +crypto_secretbox_easy(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded). +crypto_secretbox_easy_b(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded). +crypto_secretbox_open_easy(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded). +crypto_secretbox_open_easy_b(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded). crypto_stream_chacha20_KEYBYTES() -> erlang:nif_error(nif_not_loaded). crypto_stream_chacha20_NONCEBYTES() -> erlang:nif_error(nif_not_loaded). From 4eb7ec70084ba7c87b1af8797c4c4e90c84f95a2 Mon Sep 17 00:00:00 2001 From: Hans Svensson Date: Tue, 19 Mar 2024 13:23:23 +0100 Subject: [PATCH 4/6] Fix C-warnings (#10) * .envrc is not for git * Fix c code - avoid warnings * Bump Erlang versions in Github workflows --- .envrc | 1 - .github/workflows/ci.yaml | 6 +++--- .gitignore | 1 + c_src/enacl_nif.c | 5 ++--- c_src/generichash.c | 1 - c_src/kdf.c | 2 +- c_src/public.c | 2 +- c_src/secretstream.c | 2 ++ c_src/sign.c | 6 +++++- 9 files changed, 15 insertions(+), 11 deletions(-) delete mode 100644 .envrc diff --git a/.envrc b/.envrc deleted file mode 100644 index 051d09d..0000000 --- a/.envrc +++ /dev/null @@ -1 +0,0 @@ -eval "$(lorri direnv)" diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0f20072..59992d8 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -13,9 +13,9 @@ jobs: strategy: matrix: otp_vsn: - - "22.3" - - "23.3" - - "24.0" + - "24.3" + - "25.3" + - "26.2" os: - ubuntu-latest steps: diff --git a/.gitignore b/.gitignore index 870be65..e248614 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .rebar .rebar3 +.envrc ebin *.beam *.o diff --git a/c_src/enacl_nif.c b/c_src/enacl_nif.c index 5f67ab4..1a8556f 100644 --- a/c_src/enacl_nif.c +++ b/c_src/enacl_nif.c @@ -54,9 +54,8 @@ static int enacl_crypto_upgrade(ErlNifEnv* env, void **priv_data, return 0; } -static int enacl_crypto_unload(ErlNifEnv* env, void **priv_data, - ERL_NIF_TERM load_info) { - return 0; +static void enacl_crypto_unload(ErlNifEnv* env, void *priv_data) { + return; } /* GENERAL ROUTINES diff --git a/c_src/generichash.c b/c_src/generichash.c index 8f184a3..b15a14e 100644 --- a/c_src/generichash.c +++ b/c_src/generichash.c @@ -221,7 +221,6 @@ ERL_NIF_TERM enacl_crypto_generichash_update(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) { ERL_NIF_TERM ret; ErlNifBinary data; - unsigned int data_size; enacl_generichash_ctx *obj = NULL; // Validate the arguments diff --git a/c_src/kdf.c b/c_src/kdf.c index 5290513..ff6c8fe 100644 --- a/c_src/kdf.c +++ b/c_src/kdf.c @@ -20,7 +20,7 @@ ERL_NIF_TERM enacl_crypto_kdf_CONTEXTBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM enacl_crypto_kdf_derive_from_key(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) { ErlNifBinary m, c, r; - uint64_t id; + ErlNifUInt64 id; // Validate the arguments if ((argc != 3) || diff --git a/c_src/public.c b/c_src/public.c index f2113a8..623e41d 100644 --- a/c_src/public.c +++ b/c_src/public.c @@ -90,7 +90,7 @@ ERL_NIF_TERM enacl_crypto_box(ErlNifEnv *env, int argc, goto bad_arg; if (!enif_alloc_binary(padded_msg.size, &result)) { - goto done; + goto err; } if (0 != crypto_box(result.data, padded_msg.data, padded_msg.size, nonce.data, diff --git a/c_src/secretstream.c b/c_src/secretstream.c index 51414e7..2215b61 100644 --- a/c_src/secretstream.c +++ b/c_src/secretstream.c @@ -227,11 +227,13 @@ ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_init_pull( obj->state = enif_alloc(crypto_secretstream_xchacha20poly1305_statebytes()); if (obj->state == NULL) { + ret = enacl_internal_error(env); goto release; } obj->alive = 1; if ((obj->mtx = enif_mutex_create("enacl.secretstream")) == NULL) { + ret = enacl_internal_error(env); goto free; } diff --git a/c_src/sign.c b/c_src/sign.c index fb06203..1a8622e 100644 --- a/c_src/sign.c +++ b/c_src/sign.c @@ -62,6 +62,7 @@ ERL_NIF_TERM enacl_crypto_sign_init(ErlNifEnv *env, int argc, obj->alive = 0; obj->state = enif_alloc(crypto_sign_statebytes()); if (obj->state == NULL) { + ret = enacl_internal_error(env); goto release; } obj->alive = 1; @@ -82,6 +83,7 @@ ERL_NIF_TERM enacl_crypto_sign_init(ErlNifEnv *env, int argc, bad_arg: return enif_make_badarg(env); free: + ret = enacl_internal_error(env); if (obj->alive) if (obj->state != NULL) { sodium_memzero(obj->state, crypto_sign_statebytes()); @@ -285,7 +287,9 @@ enacl_crypto_sign_ed25519_public_to_curve25519(ErlNifEnv *env, int argc, return enacl_internal_error(env); } - crypto_sign_ed25519_pk_to_curve25519(curve25519_pk.data, ed25519_pk.data); + if (crypto_sign_ed25519_pk_to_curve25519(curve25519_pk.data, ed25519_pk.data) != 0) { + return enacl_internal_error(env); + } return enif_make_binary(env, &curve25519_pk); } From c1b076ad241d1c83cdc2e70bfb1dec2712661321 Mon Sep 17 00:00:00 2001 From: Hans Svensson Date: Fri, 1 Oct 2021 11:04:47 +0200 Subject: [PATCH 5/6] Expose the ed25519 API This adds a low-level APIs to perform computations over the edwards25519 curve, only useful to implement custom constructions. Exposed functions: crypto_ed25519_scalarmult/2, crypto_ed25519_scalarmult_base/1, crypto_ed25519_scalarmult_noclamp/2, crypto_ed25519_scalarmult_base_noclamp/1, crypto_ed25519_add/2, crypto_ed25519_sub/2, crypto_ed25519_is_valid_point/1, crypto_ed25519_scalar_reduce/1, crypto_ed25519_scalar_negate/1, crypto_ed25519_scalar_add/2, crypto_ed25519_scalar_sub/2, crypto_ed25519_scalar_mul/2 --- c_src/ed25519.c | 353 +++++++++++++++++++++++++++++++++++++++++ c_src/ed25519.h | 41 +++++ c_src/enacl_nif.c | 17 ++ eqc_test/enacl_eqc.erl | 65 +++++++- src/enacl.erl | 89 ++++++++++- src/enacl_nif.erl | 28 +++- 6 files changed, 590 insertions(+), 3 deletions(-) create mode 100644 c_src/ed25519.c create mode 100644 c_src/ed25519.h diff --git a/c_src/ed25519.c b/c_src/ed25519.c new file mode 100644 index 0000000..a251ac0 --- /dev/null +++ b/c_src/ed25519.c @@ -0,0 +1,353 @@ +#include +#include + +#include + +#include "enacl.h" +#include "ed25519.h" + +ERL_NIF_TERM +enacl_crypto_ed25519_is_valid_point(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary p; + + if ((argc != 1) || + (!enif_inspect_binary(env, argv[0], &p)) || + (p.size != crypto_core_ed25519_BYTES)) { + return enif_make_badarg(env); + } + + if (1 == crypto_core_ed25519_is_valid_point(p.data)) { + return enif_make_atom(env, "true"); + } else { + return enif_make_atom(env, "false"); + } +} + +ERL_NIF_TERM +enacl_crypto_ed25519_add(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ERL_NIF_TERM result; + ErlNifBinary p, q, output; + + if ((argc != 2) || + (!enif_inspect_binary(env, argv[0], &p)) || + (!enif_inspect_binary(env, argv[1], &q)) || + (p.size != crypto_core_ed25519_BYTES) || + (q.size != crypto_core_ed25519_BYTES)) { + return enif_make_badarg(env); + } + + do { + if (!enif_alloc_binary(crypto_core_ed25519_BYTES, &output)) { + result = enacl_internal_error(env); + continue; + } + + if (crypto_core_ed25519_add(output.data, p.data, q.data) != 0) { + enif_release_binary(&output); + result = enacl_error_tuple(env, "ed25519_add_failed"); + continue; + } + + result = enif_make_binary(env, &output); + } while (0); + + return result; +} + +ERL_NIF_TERM +enacl_crypto_ed25519_sub(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ERL_NIF_TERM result; + ErlNifBinary p, q, output; + + if ((argc != 2) || + (!enif_inspect_binary(env, argv[0], &p)) || + (!enif_inspect_binary(env, argv[1], &q)) || + (p.size != crypto_core_ed25519_BYTES) || + (q.size != crypto_core_ed25519_BYTES)) { + return enif_make_badarg(env); + } + + do { + if (!enif_alloc_binary(crypto_core_ed25519_BYTES, &output)) { + result = enacl_internal_error(env); + continue; + } + + if (crypto_core_ed25519_sub(output.data, p.data, q.data) != 0) { + enif_release_binary(&output); + result = enacl_error_tuple(env, "ed25519_sub_failed"); + continue; + } + + result = enif_make_binary(env, &output); + } while (0); + + return result; +} + +ERL_NIF_TERM +enacl_crypto_ed25519_scalarmult(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ERL_NIF_TERM result; + ErlNifBinary secret, basepoint, output; + uint8_t bp[crypto_scalarmult_ed25519_BYTES]; + + if ((argc != 2) || (!enif_inspect_binary(env, argv[0], &secret)) || + (!enif_inspect_binary(env, argv[1], &basepoint)) || + (secret.size != crypto_scalarmult_ed25519_BYTES) || + (basepoint.size != crypto_scalarmult_ed25519_BYTES)) { + return enif_make_badarg(env); + } + + memcpy(bp, basepoint.data, crypto_scalarmult_ed25519_BYTES); + + /* Clear the high-bit. Better safe than sorry. */ + bp[crypto_scalarmult_curve25519_BYTES - 1] &= 0x7f; + + do { + if (!enif_alloc_binary(crypto_scalarmult_curve25519_BYTES, &output)) { + result = enacl_internal_error(env); + continue; + } + + if (crypto_scalarmult_ed25519(output.data, secret.data, bp) != 0) { + enif_release_binary(&output); + result = enacl_error_tuple(env, "scalarmult_ed25519_failed"); + continue; + } + + result = enif_make_binary(env, &output); + } while (0); + + sodium_memzero(bp, crypto_scalarmult_curve25519_BYTES); + + return result; +} + +ERL_NIF_TERM +enacl_crypto_ed25519_scalarmult_base(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ERL_NIF_TERM result; + ErlNifBinary secret, output; + + if ((argc != 1) || (!enif_inspect_binary(env, argv[0], &secret)) || + (secret.size != crypto_scalarmult_ed25519_BYTES)) { + return enif_make_badarg(env); + } + + do { + if (!enif_alloc_binary(crypto_scalarmult_ed25519_BYTES, &output)) { + result = enacl_internal_error(env); + continue; + } + + if (crypto_scalarmult_ed25519_base(output.data, secret.data) != 0) { + enif_release_binary(&output); + result = enacl_error_tuple(env, "scalarmult_ed25519_base_failed"); + continue; + } + + result = enif_make_binary(env, &output); + } while (0); + + return result; +} + +ERL_NIF_TERM +enacl_crypto_ed25519_scalarmult_noclamp(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ERL_NIF_TERM result; + ErlNifBinary secret, basepoint, output; + uint8_t bp[crypto_scalarmult_ed25519_BYTES]; + + if ((argc != 2) || (!enif_inspect_binary(env, argv[0], &secret)) || + (!enif_inspect_binary(env, argv[1], &basepoint)) || + (secret.size != crypto_scalarmult_ed25519_BYTES) || + (basepoint.size != crypto_scalarmult_ed25519_BYTES)) { + return enif_make_badarg(env); + } + + memcpy(bp, basepoint.data, crypto_scalarmult_ed25519_BYTES); + + /* Clear the high-bit. Better safe than sorry. */ + bp[crypto_scalarmult_curve25519_BYTES - 1] &= 0x7f; + + do { + if (!enif_alloc_binary(crypto_scalarmult_curve25519_BYTES, &output)) { + result = enacl_internal_error(env); + continue; + } + + if (crypto_scalarmult_ed25519_noclamp(output.data, secret.data, bp) != 0) { + enif_release_binary(&output); + result = enacl_error_tuple(env, "scalarmult_ed25519_noclamp_failed"); + continue; + } + + result = enif_make_binary(env, &output); + } while (0); + + sodium_memzero(bp, crypto_scalarmult_curve25519_BYTES); + + return result; +} + +ERL_NIF_TERM +enacl_crypto_ed25519_scalarmult_base_noclamp(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ERL_NIF_TERM result; + ErlNifBinary secret, output; + + if ((argc != 1) || (!enif_inspect_binary(env, argv[0], &secret)) || + (secret.size != crypto_scalarmult_ed25519_BYTES)) { + return enif_make_badarg(env); + } + + do { + if (!enif_alloc_binary(crypto_scalarmult_ed25519_BYTES, &output)) { + result = enacl_internal_error(env); + continue; + } + + if (crypto_scalarmult_ed25519_base_noclamp(output.data, secret.data) != 0) { + enif_release_binary(&output); + result = enacl_error_tuple(env, "scalarmult_ed25519_base_noclamp_failed"); + continue; + } + + result = enif_make_binary(env, &output); + } while (0); + + return result; +} + +ERL_NIF_TERM +enacl_crypto_ed25519_scalar_reduce(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ERL_NIF_TERM result; + ErlNifBinary scalar, output; + + if ((argc != 1) || (!enif_inspect_binary(env, argv[0], &scalar)) || + (scalar.size != crypto_core_ed25519_NONREDUCEDSCALARBYTES)) { + return enif_make_badarg(env); + } + + do { + if (!enif_alloc_binary(crypto_core_ed25519_SCALARBYTES, &output)) { + result = enacl_internal_error(env); + continue; + } + + crypto_core_ed25519_scalar_reduce(output.data, scalar.data); + result = enif_make_binary(env, &output); + } while (0); + + return result; +} + +ERL_NIF_TERM +enacl_crypto_ed25519_scalar_negate(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ERL_NIF_TERM result; + ErlNifBinary scalar, output; + + if ((argc != 1) || (!enif_inspect_binary(env, argv[0], &scalar)) || + (scalar.size != crypto_core_ed25519_SCALARBYTES)) { + return enif_make_badarg(env); + } + + do { + if (!enif_alloc_binary(crypto_core_ed25519_SCALARBYTES, &output)) { + result = enacl_internal_error(env); + continue; + } + + crypto_core_ed25519_scalar_negate(output.data, scalar.data); + result = enif_make_binary(env, &output); + } while (0); + + return result; +} + +ERL_NIF_TERM +enacl_crypto_ed25519_scalar_add(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ERL_NIF_TERM result; + ErlNifBinary x, y, output; + + if ((argc != 2) || (!enif_inspect_binary(env, argv[0], &x)) || + (!enif_inspect_binary(env, argv[1], &y)) || + (x.size != crypto_core_ed25519_SCALARBYTES) || + (y.size != crypto_core_ed25519_SCALARBYTES)) { + return enif_make_badarg(env); + } + + do { + if (!enif_alloc_binary(crypto_core_ed25519_SCALARBYTES, &output)) { + result = enacl_internal_error(env); + continue; + } + + crypto_core_ed25519_scalar_add(output.data, x.data, y.data); + result = enif_make_binary(env, &output); + } while (0); + + return result; +} + +ERL_NIF_TERM +enacl_crypto_ed25519_scalar_sub(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ERL_NIF_TERM result; + ErlNifBinary x, y, output; + + if ((argc != 2) || (!enif_inspect_binary(env, argv[0], &x)) || + (!enif_inspect_binary(env, argv[1], &y)) || + (x.size != crypto_core_ed25519_SCALARBYTES) || + (y.size != crypto_core_ed25519_SCALARBYTES)) { + return enif_make_badarg(env); + } + + do { + if (!enif_alloc_binary(crypto_core_ed25519_SCALARBYTES, &output)) { + result = enacl_internal_error(env); + continue; + } + + crypto_core_ed25519_scalar_sub(output.data, x.data, y.data); + result = enif_make_binary(env, &output); + } while (0); + + return result; +} + +ERL_NIF_TERM +enacl_crypto_ed25519_scalar_mul(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ERL_NIF_TERM result; + ErlNifBinary x, y, output; + + if ((argc != 2) || (!enif_inspect_binary(env, argv[0], &x)) || + (!enif_inspect_binary(env, argv[1], &y)) || + (x.size != crypto_core_ed25519_SCALARBYTES) || + (y.size != crypto_core_ed25519_SCALARBYTES)) { + return enif_make_badarg(env); + } + + do { + if (!enif_alloc_binary(crypto_core_ed25519_SCALARBYTES, &output)) { + result = enacl_internal_error(env); + continue; + } + + crypto_core_ed25519_scalar_mul(output.data, x.data, y.data); + result = enif_make_binary(env, &output); + } while (0); + + return result; +} + + diff --git a/c_src/ed25519.h b/c_src/ed25519.h new file mode 100644 index 0000000..6fdeec5 --- /dev/null +++ b/c_src/ed25519.h @@ -0,0 +1,41 @@ +#ifndef ENACL_ED25519_H +#define ENACL_ED25519_H + +#include + +ERL_NIF_TERM enacl_crypto_ed25519_scalarmult(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_ed25519_scalarmult_base(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_ed25519_scalarmult_noclamp( + ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_ed25519_scalarmult_base_noclamp( + ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_ed25519_add(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_ed25519_sub(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_ed25519_is_valid_point(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_ed25519_scalar_reduce(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_ed25519_scalar_negate(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_ed25519_scalar_add(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_ed25519_scalar_sub(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_ed25519_scalar_mul(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); +#endif diff --git a/c_src/enacl_nif.c b/c_src/enacl_nif.c index 1a8556f..097b15e 100644 --- a/c_src/enacl_nif.c +++ b/c_src/enacl_nif.c @@ -4,6 +4,7 @@ #include #include "aead.h" +#include "ed25519.h" #include "enacl.h" #include "enacl_ext.h" #include "generichash.h" @@ -324,6 +325,22 @@ static ErlNifFunc nif_funcs[] = { enacl_crypto_curve25519_scalarmult), erl_nif_dirty_job_cpu_bound_macro("crypto_curve25519_scalarmult_base", 1, enacl_crypto_curve25519_scalarmult_base), + erl_nif_dirty_job_cpu_bound_macro("crypto_ed25519_scalarmult", 2, + enacl_crypto_ed25519_scalarmult), + erl_nif_dirty_job_cpu_bound_macro("crypto_ed25519_scalarmult_base", 1, + enacl_crypto_ed25519_scalarmult_base), + erl_nif_dirty_job_cpu_bound_macro("crypto_ed25519_scalarmult_noclamp", 2, + enacl_crypto_ed25519_scalarmult_noclamp), + erl_nif_dirty_job_cpu_bound_macro("crypto_ed25519_scalarmult_base_noclamp", + 1, enacl_crypto_ed25519_scalarmult_base_noclamp), + {"crypto_ed25519_is_valid_point", 1, enacl_crypto_ed25519_is_valid_point}, + {"crypto_ed25519_add", 2, enacl_crypto_ed25519_add}, + {"crypto_ed25519_sub", 2, enacl_crypto_ed25519_sub}, + {"crypto_ed25519_scalar_reduce", 1, enacl_crypto_ed25519_scalar_reduce}, + {"crypto_ed25519_scalar_negate", 1, enacl_crypto_ed25519_scalar_negate}, + {"crypto_ed25519_scalar_add", 2, enacl_crypto_ed25519_scalar_add}, + {"crypto_ed25519_scalar_sub", 2, enacl_crypto_ed25519_scalar_sub}, + {"crypto_ed25519_scalar_mul", 2, enacl_crypto_ed25519_scalar_mul}, erl_nif_dirty_job_cpu_bound_macro("crypto_sign_ed25519_keypair", 0, enacl_crypto_sign_ed25519_keypair), diff --git a/eqc_test/enacl_eqc.erl b/eqc_test/enacl_eqc.erl index cec95e6..2a4a67e 100644 --- a/eqc_test/enacl_eqc.erl +++ b/eqc_test/enacl_eqc.erl @@ -1005,7 +1005,7 @@ prop_scramble_block() -> ?FORALL({Block, Key}, {binary(16), eqc_gen:largebinary(32)}, is_binary(enacl_ext:scramble_block_16(Block, Key))). -%% Scala multiplication +%% Scalar multiplication prop_scalarmult() -> Bytes = 32, ?FORALL({S1, S2, Basepoint}, {binary(Bytes), binary(Bytes), binary(Bytes)}, @@ -1055,6 +1055,69 @@ prop_secretstream() -> pull_messages(DState, Blocks, Msgs) end). +%% ED25519 +gen_ed25519_point() -> + ?LET(Scalar, noshrink(binary(32)), return(enacl:crypto_ed25519_scalarmult_base(Scalar))). + +gen_ed25519_scalar() -> + ?LET(Bin, binary(64), return(enacl:crypto_ed25519_scalar_reduce(Bin))). + +prop_ed25519_add() -> + ?FORALL({P1, P2}, {gen_ed25519_point(), gen_ed25519_point()}, + equals(enacl:crypto_ed25519_add(P1, P2), enacl:crypto_ed25519_add(P2, P1)) + ). + +prop_ed25519_sub() -> + ?FORALL({P1, P2, P3}, {gen_ed25519_point(), gen_ed25519_point(), gen_ed25519_point()}, + begin + equals(enacl:crypto_ed25519_sub(P1, enacl:crypto_ed25519_add(P2, P3)), + enacl:crypto_ed25519_sub(enacl:crypto_ed25519_sub(P1, P2), P3)) + end + ). + +prop_ed25519_addsub() -> + ?FORALL({P1, P2}, {gen_ed25519_point(), gen_ed25519_point()}, + equals(P1, enacl:crypto_ed25519_add(enacl:crypto_ed25519_sub(P1, P2), P2)) + ). + +prop_ed25519_scalarmult() -> + ?FORALL({S, P}, {gen_ed25519_scalar(), gen_ed25519_point()}, + true == enacl:crypto_ed25519_is_valid_point( + enacl:crypto_ed25519_scalarmult(S, P)) + ). + +prop_ed25519_scalarmult_base() -> + ?FORALL(S, gen_ed25519_scalar(), + true == enacl:crypto_ed25519_is_valid_point( + enacl:crypto_ed25519_scalarmult_base(S)) + ). + +prop_ed25519_scalarmult_noclamp() -> + ?FORALL({S, P}, {binary(32), gen_ed25519_point()}, + true == enacl:crypto_ed25519_is_valid_point( + enacl:crypto_ed25519_scalarmult_noclamp(S, P)) + ). + +prop_ed25519_scalarmult_base_noclamp() -> + ?FORALL(S, binary(32), + true == enacl:crypto_ed25519_is_valid_point( + enacl:crypto_ed25519_scalarmult_base_noclamp(S)) + ). + +prop_ed25519_scalar() -> + ?FORALL({S1, S2}, {gen_ed25519_scalar(), gen_ed25519_scalar()}, + equals( + enacl:crypto_ed25519_scalar_add(S1, enacl:crypto_ed25519_scalar_negate(S2)), + enacl:crypto_ed25519_scalar_sub(S1, S2) + )). + +prop_ed25519_scalar_mul() -> + ?FORALL({S1, S2}, {gen_ed25519_scalar(), gen_ed25519_scalar()}, + equals( + enacl:crypto_ed25519_scalar_mul(S1, S2), + enacl:crypto_ed25519_scalar_mul(S2, S1) + )). + %% HELPERS %% INTERNAL FUNCTIONS diff --git a/src/enacl.erl b/src/enacl.erl index 3599c70..dfe3f8b 100644 --- a/src/enacl.erl +++ b/src/enacl.erl @@ -170,7 +170,20 @@ crypto_sign_ed25519_public_to_curve25519/1, crypto_sign_ed25519_secret_to_curve25519/1, crypto_sign_ed25519_public_size/0, - crypto_sign_ed25519_secret_size/0 + crypto_sign_ed25519_secret_size/0, + + crypto_ed25519_scalarmult/2, + crypto_ed25519_scalarmult_base/1, + crypto_ed25519_scalarmult_noclamp/2, + crypto_ed25519_scalarmult_base_noclamp/1, + crypto_ed25519_add/2, + crypto_ed25519_sub/2, + crypto_ed25519_is_valid_point/1, + crypto_ed25519_scalar_reduce/1, + crypto_ed25519_scalar_negate/1, + crypto_ed25519_scalar_add/2, + crypto_ed25519_scalar_sub/2, + crypto_ed25519_scalar_mul/2 ]). %% Key exchange functions @@ -1206,6 +1219,80 @@ crypto_sign_ed25519_secret_to_curve25519(SecretKey) -> erlang:bump_reductions(?ED25519_SECRET_TO_CURVE_REDS), R. +%% @doc crypto_ed25519_valid_point/1 checks if P is a valid point on the edwards25519 curve. +%% @end. +-spec crypto_ed25519_is_valid_point(P :: binary()) -> boolean(). +crypto_ed25519_is_valid_point(P) -> + enacl_nif:crypto_ed25519_is_valid_point(P). + +%% @doc crypto_ed25519_add/2 adds the point P to the point Q. +%% @end. +-spec crypto_ed25519_add(P :: binary(), Q :: binary()) -> binary(). +crypto_ed25519_add(P, Q) -> + enacl_nif:crypto_ed25519_add(P, Q). + +%% @doc crypto_ed25519_sub/2 subtracts the point Q from the point P. +%% @end. +-spec crypto_ed25519_sub(P :: binary(), Q :: binary()) -> binary(). +crypto_ed25519_sub(P, Q) -> + enacl_nif:crypto_ed25519_sub(P, Q). + +%% @doc crypto_ed25519_scalarmult/2 does a scalar multiplication between the scalar N and the point P. +%% @end. +-spec crypto_ed25519_scalarmult(N :: binary(), P :: binary()) -> binary(). +crypto_ed25519_scalarmult(N, P) -> + enacl_nif:crypto_ed25519_scalarmult(N, P). + +%% @doc crypto_ed25519_scalarmult_base/1 compute scalar multiplication of the scalar N and the base point. +%% @end. +-spec crypto_ed25519_scalarmult_base(N :: binary()) -> binary(). +crypto_ed25519_scalarmult_base(N) -> + enacl_nif:crypto_ed25519_scalarmult_base(N). + +%% @doc crypto_ed25519_scalarmult_noclamp/2 does a scalar multiplication between the scalar N and the point P. +%% N is not clamped! +%% @end. +-spec crypto_ed25519_scalarmult_noclamp(N :: binary(), P :: binary()) -> binary(). +crypto_ed25519_scalarmult_noclamp(N, P) -> + enacl_nif:crypto_ed25519_scalarmult_noclamp(N, P). + +%% @doc crypto_ed25519_scalarmult_base_noclamp/1 compute scalar multiplication of the scalar N and the base point. +%% N is not clamped! +%% @end. +-spec crypto_ed25519_scalarmult_base_noclamp(N :: binary()) -> binary(). +crypto_ed25519_scalarmult_base_noclamp(N) -> + enacl_nif:crypto_ed25519_scalarmult_base_noclamp(N). + +%% @doc crypto_ed25519_scalar_reduce/1 reduces the scalar s to (s mod L). +%% @end. +-spec crypto_ed25519_scalar_reduce(S :: binary()) -> binary(). +crypto_ed25519_scalar_reduce(S) -> + enacl_nif:crypto_ed25519_scalar_reduce(S). + +%% @doc crypto_ed25519_scalar_negate/1 returns neg so that s + neg = 0 (mod L). +%% @end. +-spec crypto_ed25519_scalar_negate(S :: binary()) -> binary(). +crypto_ed25519_scalar_negate(S) -> + enacl_nif:crypto_ed25519_scalar_negate(S). + +%% @doc crypto_ed25519_scalar_add/2 computes the scalar x + y (mod L). +%% @end. +-spec crypto_ed25519_scalar_add(X :: binary(), Y :: binary()) -> binary(). +crypto_ed25519_scalar_add(X, Y) -> + enacl_nif:crypto_ed25519_scalar_add(X, Y). + +%% @doc crypto_ed25519_scalar_sub/2 computes the scalar x - y (mod L). +%% @end. +-spec crypto_ed25519_scalar_sub(X :: binary(), Y :: binary()) -> binary(). +crypto_ed25519_scalar_sub(X, Y) -> + enacl_nif:crypto_ed25519_scalar_sub(X, Y). + +%% @doc crypto_ed25519_scalar_mul/2 computes the scalar x - y (mod L). +%% @end. +-spec crypto_ed25519_scalar_mul(X :: binary(), Y :: binary()) -> binary(). +crypto_ed25519_scalar_mul(X, Y) -> + enacl_nif:crypto_ed25519_scalar_mul(X, Y). + -spec crypto_sign_ed25519_public_size() -> pos_integer(). crypto_sign_ed25519_public_size() -> enacl_nif:crypto_sign_ed25519_PUBLICKEYBYTES(). diff --git a/src/enacl_nif.erl b/src/enacl_nif.erl index 4630202..db96860 100644 --- a/src/enacl_nif.erl +++ b/src/enacl_nif.erl @@ -127,7 +127,20 @@ crypto_sign_ed25519_public_to_curve25519/1, crypto_sign_ed25519_secret_to_curve25519/1, crypto_sign_ed25519_PUBLICKEYBYTES/0, - crypto_sign_ed25519_SECRETKEYBYTES/0 + crypto_sign_ed25519_SECRETKEYBYTES/0, + + crypto_ed25519_scalarmult/2, + crypto_ed25519_scalarmult_base/1, + crypto_ed25519_scalarmult_noclamp/2, + crypto_ed25519_scalarmult_base_noclamp/1, + crypto_ed25519_add/2, + crypto_ed25519_sub/2, + crypto_ed25519_is_valid_point/1, + crypto_ed25519_scalar_reduce/1, + crypto_ed25519_scalar_negate/1, + crypto_ed25519_scalar_add/2, + crypto_ed25519_scalar_sub/2, + crypto_ed25519_scalar_mul/2 ]). %% Key exchange @@ -365,6 +378,19 @@ crypto_sign_ed25519_keypair() -> erlang:nif_error(nif_not_loaded). crypto_sign_ed25519_sk_to_pk(_SecretKey) -> erlang:nif_error(nif_not_loaded). crypto_sign_ed25519_public_to_curve25519(_PublicKey) -> erlang:nif_error(nif_not_loaded). crypto_sign_ed25519_secret_to_curve25519(_SecretKey) -> erlang:nif_error(nif_not_loaded). +crypto_ed25519_scalarmult(_S, _Base) -> erlang:nif_error(nif_not_loaded). +crypto_ed25519_scalarmult_base(_S) -> erlang:nif_error(nif_not_loaded). +crypto_ed25519_scalarmult_noclamp(_S, _Base) -> erlang:nif_error(nif_not_loaded). +crypto_ed25519_scalarmult_base_noclamp(_S) -> erlang:nif_error(nif_not_loaded). +crypto_ed25519_add(_X, _Y) -> erlang:nif_error(nif_not_loaded). +crypto_ed25519_sub(_X, _Y) -> erlang:nif_error(nif_not_loaded). +crypto_ed25519_is_valid_point(_P) -> erlang:nif_error(nif_not_loaded). +crypto_ed25519_scalar_reduce(_S) -> erlang:nif_error(nif_not_loaded). +crypto_ed25519_scalar_negate(_S) -> erlang:nif_error(nif_not_loaded). +crypto_ed25519_scalar_add(_X, _Y) -> erlang:nif_error(nif_not_loaded). +crypto_ed25519_scalar_sub(_X, _Y) -> erlang:nif_error(nif_not_loaded). +crypto_ed25519_scalar_mul(_X, _Y) -> erlang:nif_error(nif_not_loaded). + crypto_sign_ed25519_PUBLICKEYBYTES() -> erlang:nif_error(nif_not_loaded). crypto_sign_ed25519_SECRETKEYBYTES() -> erlang:nif_error(nif_not_loaded). From c47b1b2be351f5b8fdb8d20d0036558fd80c682b Mon Sep 17 00:00:00 2001 From: Hans Svensson Date: Tue, 25 Jan 2022 12:22:27 +0100 Subject: [PATCH 6/6] Cleanup scalarmult, fix bug + add test --- c_src/ed25519.c | 40 ++++++++++++---------------------------- eqc_test/enacl_eqc.erl | 5 +++++ 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/c_src/ed25519.c b/c_src/ed25519.c index a251ac0..69f15b4 100644 --- a/c_src/ed25519.c +++ b/c_src/ed25519.c @@ -92,28 +92,22 @@ ERL_NIF_TERM enacl_crypto_ed25519_scalarmult(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) { ERL_NIF_TERM result; - ErlNifBinary secret, basepoint, output; - uint8_t bp[crypto_scalarmult_ed25519_BYTES]; + ErlNifBinary scalar, point, output; - if ((argc != 2) || (!enif_inspect_binary(env, argv[0], &secret)) || - (!enif_inspect_binary(env, argv[1], &basepoint)) || - (secret.size != crypto_scalarmult_ed25519_BYTES) || - (basepoint.size != crypto_scalarmult_ed25519_BYTES)) { + if ((argc != 2) || (!enif_inspect_binary(env, argv[0], &scalar)) || + (!enif_inspect_binary(env, argv[1], &point)) || + (scalar.size != crypto_scalarmult_ed25519_BYTES) || + (point.size != crypto_scalarmult_ed25519_BYTES)) { return enif_make_badarg(env); } - memcpy(bp, basepoint.data, crypto_scalarmult_ed25519_BYTES); - - /* Clear the high-bit. Better safe than sorry. */ - bp[crypto_scalarmult_curve25519_BYTES - 1] &= 0x7f; - do { if (!enif_alloc_binary(crypto_scalarmult_curve25519_BYTES, &output)) { result = enacl_internal_error(env); continue; } - if (crypto_scalarmult_ed25519(output.data, secret.data, bp) != 0) { + if (crypto_scalarmult_ed25519(output.data, scalar.data, point.data) != 0) { enif_release_binary(&output); result = enacl_error_tuple(env, "scalarmult_ed25519_failed"); continue; @@ -122,8 +116,6 @@ enacl_crypto_ed25519_scalarmult(ErlNifEnv *env, int argc, result = enif_make_binary(env, &output); } while (0); - sodium_memzero(bp, crypto_scalarmult_curve25519_BYTES); - return result; } @@ -160,28 +152,22 @@ ERL_NIF_TERM enacl_crypto_ed25519_scalarmult_noclamp(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) { ERL_NIF_TERM result; - ErlNifBinary secret, basepoint, output; - uint8_t bp[crypto_scalarmult_ed25519_BYTES]; + ErlNifBinary scalar, point, output; - if ((argc != 2) || (!enif_inspect_binary(env, argv[0], &secret)) || - (!enif_inspect_binary(env, argv[1], &basepoint)) || - (secret.size != crypto_scalarmult_ed25519_BYTES) || - (basepoint.size != crypto_scalarmult_ed25519_BYTES)) { + if ((argc != 2) || (!enif_inspect_binary(env, argv[0], &scalar)) || + (!enif_inspect_binary(env, argv[1], &point)) || + (scalar.size != crypto_scalarmult_ed25519_BYTES) || + (point.size != crypto_scalarmult_ed25519_BYTES)) { return enif_make_badarg(env); } - memcpy(bp, basepoint.data, crypto_scalarmult_ed25519_BYTES); - - /* Clear the high-bit. Better safe than sorry. */ - bp[crypto_scalarmult_curve25519_BYTES - 1] &= 0x7f; - do { if (!enif_alloc_binary(crypto_scalarmult_curve25519_BYTES, &output)) { result = enacl_internal_error(env); continue; } - if (crypto_scalarmult_ed25519_noclamp(output.data, secret.data, bp) != 0) { + if (crypto_scalarmult_ed25519_noclamp(output.data, scalar.data, point.data) != 0) { enif_release_binary(&output); result = enacl_error_tuple(env, "scalarmult_ed25519_noclamp_failed"); continue; @@ -190,8 +176,6 @@ enacl_crypto_ed25519_scalarmult_noclamp(ErlNifEnv *env, int argc, result = enif_make_binary(env, &output); } while (0); - sodium_memzero(bp, crypto_scalarmult_curve25519_BYTES); - return result; } diff --git a/eqc_test/enacl_eqc.erl b/eqc_test/enacl_eqc.erl index 2a4a67e..832d693 100644 --- a/eqc_test/enacl_eqc.erl +++ b/eqc_test/enacl_eqc.erl @@ -1086,6 +1086,11 @@ prop_ed25519_scalarmult() -> enacl:crypto_ed25519_scalarmult(S, P)) ). +prop_ed25519_scalarmult_1() -> + ?FORALL(P, gen_ed25519_point(), + equals(P, enacl:crypto_ed25519_scalarmult_noclamp(<<1:256/little>>, P)) + ). + prop_ed25519_scalarmult_base() -> ?FORALL(S, gen_ed25519_scalar(), true == enacl:crypto_ed25519_is_valid_point(