Library for ed25519 signatures

I have used until now this library for ed25519 signing and verifying - https://hexdocs.pm/ed25519/Ed25519.html#content. However, I am not pleased with the library at all. The signing time is 100-120ms and the validating of a signature 150-190ms, which I think could be better. Moreover, I am unable to extract the hash (sha512) used for the signature, which I would really like to have separately.

Do you have any recommendations on a better library for ed25519?

This library is implemented purely in Elixir, of course it will be slow. If you want to have faster and built-in implementation, then compile your Erlang with modern OpenSSL (1.1+ IIRC) and then you can use :crypto module directly.

I have tried generating key using :crypto.generate_key(:ecdh, :ed25519), but Edwards curves are still not implemented in :crypto.ec_curves in order to use it (Erlang/OTP 22).

What is output of info_lib/0? Because if you have compiled with OpenSSL 1.0 then it will not have Edward’s curves as these are implemented in OpenSSL 1.1 and later. In my case:

iex> :crypto.info_lib()
[{"OpenSSL", 269488207, "OpenSSL 1.1.1d  10 Sep 2019"}]
iex> :ed25519 in :crypto.ec_curves()
true

So there is support for such.

EDIT:

Also if you check edwards_curve_dh/0 type then you will see that you need to use :x25519 instead of :ed25519 as a curve name.

1 Like

The output from info_lib/0 is the same. Creating keys worked without any issues with :x25519, but signing still fails:

:crypto.sign(:ecdsa, :sha256, "msg", [pk, :x25519])
** (ArgumentError) argument error
    (crypto) :crypto.pkey_sign_nif(:ecdsa, :sha256, "msg", {{:evp, :x25519}, <<127, 106, 130, 168, 185, 171, 210, 115, 88, 46, 158, 57, 39, 101, 193, 114, 130, 214, 69, 220, 117, 184, 188, 107, 199, 80, 49, 234, 39, 74, 176, 96>>}, [])
    (crypto) crypto.erl:1610: :crypto.sign/5

I have tried using binary instead of string for the message, passing only the key, still no luck…

Here is a discussion from 6 years back for incomplete elliptic curve implementation in Erlang, I suppose it still continues to be that way
https://erlang-bugs.erlang.narkive.com/YNWGZ1F2/incomplete-elliptic-curve-cipher-suites-in-r16b01-and-r16b02

Any opinion on the libsalty library - https://github.com/ArteMisc/libsalty?

Yes, now this fails, because when signing you need to use :ed25519 (don’t ask me why this works this way). You need to check documentation of crypto:sign/4.

I haven’t used libsalty, but if NaCL is what you need, or you just want to get crypto right without all that hassle, then it is good choice.

1 Like

why does it work this way?

Yes, with :crypto.sign(:eddsa, :sha256, msg, [priv_key, :ed25519]) worked! I get between 1.5e-4 and 2.3e-4 in time which is great.

However, :crypto.verify(:eddsa, :sha256, msg, signature, [pub_key, :ed25519]) always returns false…

EDIT:

I have tested the Salty library and works impressively good - in terms of performance it is even faster than the Erlang :crypto. For now I will stick with it.

In :crypto.generate_key(:ecdh, :ed25519) ecdh refers to all kinds of eliptic curves and then we use x25519. While in :crypto.sign(:eddsa, :sha256, msg, [priv_key, :ed25519]) we have special function for Edwards curves, in which we use ed25519.
I hope it makes a bit more sense.

1 Like

I believe :crypto.generate_key(:eddsa, :ed25519) should be used for EdDSA signatures. The curve x25519 is only used for key exchange algorithms (like ecdh). Anyway, the :eddsa, :ed25519 parameter combination seems to be supported only in Erlang 23.1.
Regarding libsalty, the repo has been archived, so I am not confident in using it.

Given this, any ideas? Perhaps the best option will be to depend on Erlang 23.1…

I think this was already solved… but I’ve been playing with the :crypto library recently and it looks like you needed to use a different parameter.

This is an easy mistake to do because of the formatting of the documenation. So, it looks like this:

edwards_curve_dh() = x25519 | x448
edwards_curve_ed() = ed25519 | ed448

But, the params for type :ecdh are the following: ecdh_params() = ec_named_curve() | edwards_curve_dh() | ec_explicit_curve()

If you switch out :ed25519 (which is edwards_curve_ed()) for :x25519, then it’ll work (assuming you’re now using erlang 23+). I’m currently on 23.2.1 and it’s working.

1 Like