ed448goldilocks (libdecaf) NIF with timeslice reductions for Erlang and Elixir.
See “Decaf: Eliminating cofactors through point compression” by Mike Hamburg for more information.
The timeslice reductions allow the NIF to perform certain operations on very large inputs without blocking the scheduler or requiring the Erlang VM to support dirty schedulers. See the bitwise project from which the strategy was derived.
Tested against the RFC 8032, FIPS 180-4, FIPS 202, and RFC 7748 test vectors.
Algorithm | Group | Purpose | Definition |
---|---|---|---|
Ed25519 | EdDSA | Signature | RFC 8032 |
Ed25519ctx | EdDSA | Signature | RFC 8032 |
Ed25519ph | EdDSA | Signature | RFC 8032 |
Ed448 | EdDSA | Signature | RFC 8032 |
Ed448ph | EdDSA | Signature | RFC 8032 |
SPONGERNG | KECCAK | Pseudo-Random | decaf/spongerng.h |
SHA2-512 | SHA-2 | Hash | FIPS 180-4 |
SHA3-224 | SHA-3 | Hash | FIPS 202 |
SHA3-256 | SHA-3 | Hash | FIPS 202 |
SHA3-384 | SHA-3 | Hash | FIPS 202 |
SHA3-512 | SHA-3 | Hash | FIPS 202 |
SHAKE128 | SHA-3 | Hash | FIPS 202 |
SHAKE256 | SHA-3 | Hash | FIPS 202 |
X25519 | ECDH | Key Exchange | RFC 7748 |
X448 | ECDH | Key Exchange | RFC 7748 |
Add libdecaf
to your project's dependencies in mix.exs
defp deps do
[
{:libdecaf, "~> 1.0"}
]
end
Add libdecaf
to your project's dependencies in your Makefile
for erlang.mk
or the following to your rebar.config
{deps, [
{libdecaf, ".*", {git, "git://github.com/potatosalad/erlang-libdecaf.git", {branch, "master"}}}
]}.
%% X25519 (curve25519) Key Generation
{AlicePK25519, AliceSK25519} = libdecaf_curve25519:x25519_keypair().
% {<<155,64,184,119,41,134,146,219,250,18,4,67,204,130,43,123,254,96,68,174,200,23,238,126,79,238,85,159,186,4,120,75>>, <<32,212,161,45,202,186,28,152,196,19,74,127,44,14,73,165,194,228,179,252,108,220,81,163,201,183,167,144,143,160,212,206>>}
{BobPK25519, BobSK25519} = libdecaf_curve25519:x25519_keypair().
% {<<31,100,69,143,46,85,11,129,240,52,225,219,164,100,9,171,242,98,210,112,8,222,150,66,16,160,143,122,102,188,146,10>>, <<39,232,51,250,201,211,41,191,120,143,42,86,105,150,4,24,169,238,245,77,238,40,179,198,96,157,144,229,162,41,205,77>>}
%% X25519 Shared Secret
SharedSecretX25519 = libdecaf_curve25519:x25519(AliceSK25519, BobPK25519).
% <<83,191,246,24,100,87,227,192,3,237,26,132,143,40,62,213,67,232,33,97,240,8,73,139,64,160,13,107,150,146,246,30>>
SharedSecretX25519 =:= libdecaf_curve25519:x25519(BobSK25519, AlicePK25519).
% true
%% X448 (curve448) Key Generation
{AlicePK448, AliceSK448} = libdecaf_curve448:x448_keypair().
% {<<105,143,129,11,70,98,185,191,191,50,127,193,175,72,161,79,83,138,120,81,31,104,18,241,113,197,243,49,93,92,165,124,198,141,92,186,199,33,67,132,244,217,138,213,64,67,106,63,33,144,227,46,158,169,74,242>>, <<167,49,168,47,44,91,156,96,5,153,110,156,108,175,53,145,63,251,245,180,129,161,206,122,26,197,27,146,248,100,74,167,70,130,43,193,21,169,118,30,80,74,145,200,176,112,94,139,59,250,167,118,103,50,209,53>>}
{BobPK448, BobSK448} = libdecaf_curve448:x448_keypair().
% {<<83,3,128,166,199,125,249,189,28,86,204,99,239,204,162,180,230,199,198,77,55,120,44,169,165,153,238,230,47,255,223,187,18,7,65,152,205,235,76,65,152,93,38,236,177,36,70,199,146,235,67,245,226,142,27,24>>, <<90,248,1,221,137,251,205,121,215,99,121,204,122,92,97,157,88,173,213,171,171,83,64,140,72,156,96,242,230,239,89,242,76,190,148,109,13,145,159,138,105,240,246,86,169,137,144,80,241,224,91,73,108,165,156,31>>}
%% X448 Shared Secret
SharedSecretX448 = libdecaf_curve448:x448(AliceSK448, BobPK448).
% <<114,107,110,164,14,165,169,174,160,230,53,253,116,87,238,193,5,2,210,229,81,43,197,195,128,229,181,13,30,139,203,164,6,24,167,53,193,173,199,233,232,41,221,244,18,176,233,77,209,27,22,90,189,218,201,227>>
SharedSecretX448 =:= libdecaf_curve448:x448(BobSK448, AlicePK448).
% true
%% EdDSA (edwards25519) Key Generation
{PK25519, SK25519} = libdecaf_curve25519:eddsa_keypair().
% {<<211,65,121,173,153,86,193,196,218,254,23,46,4,146,26,124,131,219,63,144,210,48,209,178,189,10,233,246,248,65,158,48>>, <<63,238,247,145,210,20,146,223,78,100,90,126,134,45,223,41,104,231,121,9,5,104,69,122,233,171,44,76,57,171,155,211,211,65,121,173,153,86,193,196,218,254,23,46,4,146,26,124,131,219,63,144,210,48,209,178,189,10,233,246,248,65,158,48>>}
%% EdDSA (edwards448) Key Generation
{PK448, SK448} = libdecaf_curve448:eddsa_keypair().
% {<<241,233,41,181,164,174,226,117,24,66,133,47,149,210,164,224,28,126,128,72,91,188,104,161,195,124,68,135,92,239,242,16,54,103,127,106,169,175,41,108,92,133,176,221,9,217,123,174,85,37,243,51,184,123,208,112,0>>, <<208,201,124,71,171,63,19,141,159,70,248,214,101,209,110,44,221,16,92,150,231,227,56,223,39,52,47,163,35,76,103,204,158,103,184,236,28,255,121,25,147,183,188,212,197,107,37,71,183,104,96,32,107,139,114,245,155,241,233,41,181,164,174,226,117,24,66,133,47,149,210,164,224,28,126,128,72,91,188,104,161,195,124,68,135,92,239,242,16,54,103,127,106,169,175,41,108,92,133,176,221,9,217,123,174,85,37,243,51,184,123,208,112,0>>}
The following message M
and context C
will be used for all signature examples below.
M = <<>>. % Message used below for signing
C = <<"test">>. % Context used below by Ed448 and Ed448ph
%% Ed25519 Sign
SigEd25519 = libdecaf_curve25519:ed25519_sign(M, SK25519).
% <<206,59,70,86,114,42,116,11,30,183,149,16,90,90,105,162,112,182,99,62,90,20,207,102,102,98,230,18,23,175,212,150,146,27,83,120,107,135,209,56,75,214,152,204,24,205,48,128,129,191,174,137,11,189,75,14,7,242,3,255,122,176,182,2>>
%% Ed25519 Verify
libdecaf_curve25519:ed25519_verify(SigEd25519, M, PK25519).
% true
%% Ed25519ctx Sign
SigEd25519ctx = libdecaf_curve25519:ed25519ctx_sign(M, SK25519, C).
% <<121,125,214,50,137,200,252,109,235,4,97,17,231,63,160,143,199,137,100,132,145,175,61,245,212,221,100,99,189,35,73,77,245,64,153,81,110,135,155,211,105,100,232,173,157,219,89,197,185,173,83,83,136,183,47,69,41,27,81,37,28,120,127,0>>
%% Ed25519ctx Verify
libdecaf_curve25519:ed25519ctx_verify(SigEd25519ctx, M, PK25519, C).
% true
%% Ed25519ph Sign
SigEd25519ph = libdecaf_curve25519:ed25519ph_sign(M, SK25519).
% <<38,138,35,252,20,194,155,187,120,255,150,145,241,64,155,210,107,134,239,171,190,219,2,221,254,79,19,187,208,183,18,156,190,45,181,85,100,10,19,108,180,189,207,24,244,9,44,13,69,215,88,57,227,71,72,50,84,134,211,28,160,175,164,15>>
%% Ed25519ph Verify
libdecaf_curve25519:ed25519ph_verify(SigEd25519ph, M, PK25519).
% true
%% Ed448 Sign
SigEd448 = libdecaf_curve448:ed448_sign(M, SK448).
% <<119,207,247,95,201,79,152,97,43,180,45,185,35,106,183,196,49,213,79,187,29,138,177,18,179,169,69,199,186,168,245,4,237,201,28,60,238,248,239,35,24,16,96,225,82,210,43,71,15,26,235,67,34,209,41,34,0,196,180,145,251,47,102,57,80,10,3,131,169,40,130,129,165,20,33,208,230,218,127,231,61,84,146,237,77,239,56,241,73,165,24,89,55,149,175,238,154,238,27,88,206,242,238,5,161,22,157,229,47,171,26,168,6,0>>
%% Ed448 Verify
libdecaf_curve448:ed448_verify(SigEd448, M, PK448).
% true
%% Ed448 Sign with Context
SigEd448C = libdecaf_curve448:ed448_sign(M, SK448, C).
% <<198,30,160,202,201,28,194,205,148,240,61,130,243,165,24,200,41,118,93,214,56,253,177,171,146,176,149,237,247,108,171,59,123,218,127,48,4,191,227,3,193,177,33,211,120,44,104,86,71,202,97,76,109,41,178,54,0,214,106,192,185,186,130,72,187,199,95,189,203,25,173,26,36,89,1,91,220,192,18,141,7,168,190,107,76,243,251,56,248,121,183,193,138,72,130,96,119,44,97,69,224,186,129,29,205,60,242,222,247,123,130,7,54,0>>
%% Ed448 Verify with Context
libdecaf_curve448:ed448_verify(SigEd448C, M, PK448, C).
% true
%% Ed448ph Sign
SigEd448ph = libdecaf_curve448:ed448ph_sign(M, SK448).
% <<61,28,185,125,227,93,73,177,186,177,224,87,60,237,63,115,204,239,209,169,157,197,155,42,67,29,32,148,120,33,52,6,40,207,172,33,82,122,134,20,59,153,62,159,69,229,218,26,163,145,20,237,15,54,164,101,128,204,197,240,72,160,203,235,124,201,33,215,72,197,140,53,203,165,55,190,209,166,212,90,29,69,89,136,159,83,55,110,11,22,45,222,98,164,8,237,166,57,180,150,63,126,227,124,239,6,131,62,140,135,234,94,20,0>>
%% Ed448 Verify
libdecaf_curve448:ed448ph_verify(SigEd448ph, M, PK448).
% true
%% Ed448ph Sign with Context
SigEd448phC = libdecaf_curve448:ed448ph_sign(M, SK448, C).
% <<231,37,236,141,234,175,12,81,19,66,127,155,15,245,146,181,254,95,216,109,5,90,94,219,70,51,211,22,42,172,96,248,227,95,109,101,142,17,76,5,71,111,73,138,157,28,214,114,69,126,50,44,234,241,25,142,128,199,224,67,223,66,203,103,92,103,153,207,116,200,158,81,228,140,64,67,69,143,112,128,92,229,218,76,149,33,31,79,55,242,221,19,168,143,31,197,73,95,148,73,143,107,18,217,63,136,43,25,218,20,124,118,37,0>>
%% Ed448ph Verify with Context
libdecaf_curve448:ed448ph_verify(SigEd448phC, M, PK448, C).
% true
This function allows you to specify an initial seed buffer and whether the PRNG will be deterministic or not.
%% Deterministic
libdecaf_spongerng:init_from_buffer(<<>>, true).
% {spongerng, #Ref<0.0.0.1>}
%% Non-deterministic
libdecaf_spongerng:init_from_buffer(<<>>, false).
% {spongerng, #Ref<0.0.0.2>}
This function allows you specify an initial seed file up to the given length and whether the PRNG will be deterministic or not.
%% Deterministic
libdecaf_spongerng:init_from_file("seed.txt", 16, true).
% {spongerng, #Ref<0.0.0.3>}
%% Non-deterministic
libdecaf_spongerng:init_from_file("seed.txt", 16, false).
% {spongerng, #Ref<0.0.0.4>}
This function reads an initial seed from /dev/urandom
and is only allowed to be non-deterministic.
%% Non-deterministic
libdecaf_spongerng:init_from_dev_urandom().
% {spongerng, #Ref<0.0.0.5>}
This function returns the next length of bytes from the sponge and returns the new sponge state.
Sponge0 = libdecaf_spongerng:init_from_buffer(<<>>, true),
{Sponge1, Output} = libdecaf_spongerng:next(Sponge0, 8).
% {{spongerng, #Ref<0.0.0.6>}, <<99,190,253,62,125,162,80,150>>}
This function modifies the sponge state (stirs the pot) with the given input.
Sponge0 = libdecaf_spongerng:init_from_buffer(<<>>, true),
Sponge1 = libdecaf_spongerng:stir(Sponge0, <<"test">>),
{Sponge2, Output} = libdecaf_spongerng:next(Sponge1, 8).
% {{spongerng, #Ref<0.0.0.7>}, <<168,214,5,0,60,110,186,33>>}
This function can be used for the following algorithms:
- SHA2-512 (
sha2_512
)
libdecaf_sha2:hash(sha2_512, <<"test">>).
% <<238,38,176,221,74,247,231,73,170,26,142,227,193,10,233,146,63,97,137,128,119,46,71,63,136,25,165,212,148,14,13,178,122,193,133,248,160,225,213,248,79,136,188,136,127,214,123,20,55,50,195,4,204,95,169,173,142,111,87,245,0,40,168,255>>
This function can be used for the following algorithms:
- SHA2-512 (
sha2_512
)
Context0 = libdecaf_sha2:init(sha2_512).
% {sha2_512, #Ref<0.0.0.1>}
This function can be used for the following algorithms:
- SHA2-512 (
sha2_512
)
The examples below use the Context0
for each algorithm from the examples above for libdecaf_sha2:init/1
.
Context1 = libdecaf_sha2:update(Context0, <<"test">>).
% {sha2_512, #Ref<0.0.0.2>}
This function can be used for the following algorithms:
- SHA2-512 (
sha2_512
)
The examples below use the Context1
for each algorithm from the examples above for libdecaf_sha2:update/2
.
Out = libdecaf_sha2:final(Context1).
% <<238,38,176,221,74,247,231,73,170,26,142,227,193,10,233,146,63,97,137,128,119,46,71,63,136,25,165,212,148,14,13,178,122,193,133,248,160,225,213,248,79,136,188,136,127,214,123,20,55,50,195,4,204,95,169,173,142,111,87,245,0,40,168,255>>
This function can be used for the following algorithms:
- SHA3-224 (
sha3_224
) - SHA3-256 (
sha3_256
) - SHA3-384 (
sha3_384
) - SHA3-512 (
sha3_512
)
libdecaf_sha3:hash(sha3_224, <<"test">>).
% <<55,151,191,10,251,191,202,74,123,187,167,96,42,43,85,39,70,135,101,23,167,249,183,206,45,176,174,123>>
libdecaf_sha3:hash(sha3_256, <<"test">>).
% <<54,240,40,88,11,176,44,200,39,42,154,2,15,66,0,227,70,226,118,174,102,78,69,238,128,116,85,116,226,245,171,128>>
libdecaf_sha3:hash(sha3_384, <<"test">>).
% <<229,22,218,187,35,182,227,0,38,134,53,67,40,39,128,163,174,13,204,240,85,81,207,2,149,23,141,127,240,241,180,30,236,185,219,63,242,25,0,124,78,9,114,96,213,134,33,189>>
libdecaf_sha3:hash(sha3_512, <<"test">>).
% <<158,206,8,110,155,172,73,31,172,92,29,16,70,202,17,215,55,185,42,43,46,189,147,240,5,215,183,16,17,12,10,103,130,136,22,110,127,190,121,104,131,164,242,233,179,202,159,72,79,82,29,12,228,100,52,92,193,174,201,103,121,20,156,20>>
This function can be used for the following algorithms:
- SHAKE128 (
shake128
) - SHAKE256 (
shake256
)
These algorithms can output arbitrary length digests, so an output length must be specified.
libdecaf_sha3:hash(shake128, <<"test">>, 16).
% <<211,176,170,156,216,183,37,86,34,206,188,99,30,134,125,64>>
libdecaf_sha3:hash(shake256, <<"test">>, 16).
% <<181,79,247,37,87,5,167,30,226,146,94,74,62,48,228,26>>
This function can be used for the following algorithms:
- SHA3-224 (
sha3_224
) - SHA3-256 (
sha3_256
) - SHA3-384 (
sha3_384
) - SHA3-512 (
sha3_512
) - SHAKE128 (
shake128
) - SHAKE256 (
shake256
)
Sponge0 = libdecaf_sha3:init(sha3_224).
% {sha3_224, #Ref<0.0.0.3>}
Sponge0 = libdecaf_sha3:init(sha3_256).
% {sha3_256, #Ref<0.0.0.4>}
Sponge0 = libdecaf_sha3:init(sha3_384).
% {sha3_384, #Ref<0.0.0.5>}
Sponge0 = libdecaf_sha3:init(sha3_512).
% {sha3_512, #Ref<0.0.0.6>}
Sponge0 = libdecaf_sha3:init(shake128).
% {shake128, #Ref<0.0.0.7>}
Sponge0 = libdecaf_sha3:init(shake256).
% {shake256, #Ref<0.0.0.8>}
This function can be used for the following algorithms:
- SHA3-224 (
sha3_224
) - SHA3-256 (
sha3_256
) - SHA3-384 (
sha3_384
) - SHA3-512 (
sha3_512
) - SHAKE128 (
shake128
) - SHAKE256 (
shake256
)
The examples below use the Sponge0
for each algorithm from the examples above for libdecaf_sha3:init/1
.
Sponge1 = libdecaf_sha3:update(Sponge0, <<"test">>).
% {sha3_224, #Ref<0.0.0.9>}
Sponge1 = libdecaf_sha3:update(Sponge0, <<"test">>).
% {sha3_256, #Ref<0.0.0.10>}
Sponge1 = libdecaf_sha3:update(Sponge0, <<"test">>).
% {sha3_384, #Ref<0.0.0.11>}
Sponge1 = libdecaf_sha3:update(Sponge0, <<"test">>).
% {sha3_512, #Ref<0.0.0.12>}
Sponge1 = libdecaf_sha3:update(Sponge0, <<"test">>).
% {shake128, #Ref<0.0.0.13>}
Sponge1 = libdecaf_sha3:update(Sponge0, <<"test">>).
% {shake256, #Ref<0.0.0.14>}
This function can be used for the following algorithms:
- SHA3-224 (
sha3_224
) - SHA3-256 (
sha3_256
) - SHA3-384 (
sha3_384
) - SHA3-512 (
sha3_512
)
The examples below use the Sponge1
for each algorithm from the examples above for libdecaf_sha3:update/2
.
Out = libdecaf_sha3:final(Sponge1).
% <<55,151,191,10,251,191,202,74,123,187,167,96,42,43,85,39,70,135,101,23,167,249,183,206,45,176,174,123>>
Out = libdecaf_sha3:final(Sponge1).
% <<54,240,40,88,11,176,44,200,39,42,154,2,15,66,0,227,70,226,118,174,102,78,69,238,128,116,85,116,226,245,171,128>>
Out = libdecaf_sha3:final(Sponge1).
% <<229,22,218,187,35,182,227,0,38,134,53,67,40,39,128,163,174,13,204,240,85,81,207,2,149,23,141,127,240,241,180,30,236,185,219,63,242,25,0,124,78,9,114,96,213,134,33,189>>
Out = libdecaf_sha3:final(Sponge1).
% <<158,206,8,110,155,172,73,31,172,92,29,16,70,202,17,215,55,185,42,43,46,189,147,240,5,215,183,16,17,12,10,103,130,136,22,110,127,190,121,104,131,164,242,233,179,202,159,72,79,82,29,12,228,100,52,92,193,174,201,103,121,20,156,20>>
This function can be used for the following algorithms:
- SHA3-224 (
sha3_224
) - SHA3-256 (
sha3_256
) - SHA3-384 (
sha3_384
) - SHA3-512 (
sha3_512
)
These algorithms can output arbitrary length digests, so an output length must be specified.
The examples below use the Sponge1
for each algorithm from the examples above for libdecaf_sha3:update/2
.
Out = libdecaf_sha3:final(Sponge1, 16).
% <<211,176,170,156,216,183,37,86,34,206,188,99,30,134,125,64>>
Out = libdecaf_sha3:final(Sponge1, 16).
% <<181,79,247,37,87,5,167,30,226,146,94,74,62,48,228,26>>