Compare commits
15 Commits
8b2fd35408
...
testie
| Author | SHA1 | Date | |
|---|---|---|---|
| 14cb92e7ab | |||
| eebfedd810 | |||
| 4c1af8bbf3 | |||
| 30944928da | |||
| 0c36c788ed | |||
| c262d63c89 | |||
| 0904ed3283 | |||
| 8de9eefd75 | |||
| 573b0fd1bb | |||
| 9db7c9220e | |||
| 0dad93cf3c | |||
| 5a0d41bd62 | |||
| bf8623e9fc | |||
| 5d7f6349ac | |||
| 0a82f63d93 |
@@ -0,0 +1,15 @@
|
|||||||
|
name: EC Utils Tests
|
||||||
|
run-name: ${{ gitea.actor }} testing EC Utils
|
||||||
|
on: [push, workflow_dispatch]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
tests:
|
||||||
|
runs-on: linux_amd64
|
||||||
|
steps:
|
||||||
|
- name: Check out repository code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: test
|
||||||
|
run: |
|
||||||
|
. /opt/act_runner/erts/27.2/activate
|
||||||
|
./rebar3 dialyzer
|
||||||
|
./rebar3 eunit
|
||||||
+5
-5
@@ -3,8 +3,8 @@
|
|||||||
{registered,[]},
|
{registered,[]},
|
||||||
{included_applications,[]},
|
{included_applications,[]},
|
||||||
{applications,[stdlib,kernel]},
|
{applications,[stdlib,kernel]},
|
||||||
{vsn,"0.1.0"},
|
{vsn,"1.0.1"},
|
||||||
{modules,[ed25519_eqc,eddsa_eqc,ec_utils,ecu_crypto,ecu_ecdsa,
|
{modules,[ecu_crypto_eqc,ed25519_eqc,eddsa_eqc,ec_utils,
|
||||||
ecu_ed25519,ecu_eddsa,ecu_misc,ecu_secp256k1,
|
ecu_crypto,ecu_ecdsa,ecu_ed25519,ecu_eddsa,ecu_misc,
|
||||||
benchmark_tests,crypto_tests,ecdsa_tests,
|
ecu_secp256k1,benchmark_tests,crypto_tests,
|
||||||
secp256k1_tests]}]}.
|
ecdsa_tests,secp256k1_tests]}]}.
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
%%% File : ecu_crypto_eqc.erl
|
||||||
|
%%% Author : Hans Svensson
|
||||||
|
%%% Description :
|
||||||
|
%%% Created : 7 Jan 2023 by Hans Svensson
|
||||||
|
-module(ecu_crypto_eqc).
|
||||||
|
|
||||||
|
-compile([export_all, nowarn_export_all]).
|
||||||
|
|
||||||
|
-include_lib("eqc/include/eqc.hrl").
|
||||||
|
|
||||||
|
gen_ecdsa_secp256k1_privkey() ->
|
||||||
|
<<P0:256>> = crypto:strong_rand_bytes(32),
|
||||||
|
P = (P0 rem (ecu_secp256k1:n() - 1)) + 1,
|
||||||
|
return(<<P:256>>).
|
||||||
|
|
||||||
|
prop_recover() ->
|
||||||
|
?FORALL(PK, gen_ecdsa_secp256k1_privkey(),
|
||||||
|
begin
|
||||||
|
MsgHash = sha3:hash(256, PK),
|
||||||
|
Sig = ecu_crypto:eth_sign(MsgHash, PK),
|
||||||
|
Pub1 = ecrecover:recover(MsgHash, Sig),
|
||||||
|
Pub2 = ecu_crypto:ec_recover(MsgHash, Sig),
|
||||||
|
equals(Pub1, Pub2)
|
||||||
|
end).
|
||||||
|
|
||||||
+7
-7
@@ -17,12 +17,12 @@ gen_scalar() ->
|
|||||||
?LET(N, gen_large_n(), <<N:256/little>>).
|
?LET(N, gen_large_n(), <<N:256/little>>).
|
||||||
|
|
||||||
gen_point() ->
|
gen_point() ->
|
||||||
?LET(S, gen_scalar(), enacl:crypto_ed25519_scalarmult_base_noclamp(S)).
|
?LET(S, gen_scalar(), enacl:curve25519_scalarmult_base_noclamp(S)).
|
||||||
|
|
||||||
prop_compress() ->
|
prop_compress() ->
|
||||||
?FORALL(S, gen_scalar(),
|
?FORALL(S, gen_scalar(),
|
||||||
begin
|
begin
|
||||||
CompP = enacl:crypto_ed25519_scalarmult_base_noclamp(S),
|
CompP = enacl:curve25519_scalarmult_base_noclamp(S),
|
||||||
DecP = ecu_ed25519:scalar_mul_base_noclamp(S),
|
DecP = ecu_ed25519:scalar_mul_base_noclamp(S),
|
||||||
equals(CompP, ecu_ed25519:compress(DecP))
|
equals(CompP, ecu_ed25519:compress(DecP))
|
||||||
end).
|
end).
|
||||||
@@ -30,7 +30,7 @@ prop_compress() ->
|
|||||||
prop_decompress() ->
|
prop_decompress() ->
|
||||||
?FORALL(S, gen_scalar(),
|
?FORALL(S, gen_scalar(),
|
||||||
begin
|
begin
|
||||||
CompP = enacl:crypto_ed25519_scalarmult_base_noclamp(S),
|
CompP = enacl:curve25519_scalarmult_base_noclamp(S),
|
||||||
DecP = ecu_ed25519:scalar_mul_base_noclamp(S),
|
DecP = ecu_ed25519:scalar_mul_base_noclamp(S),
|
||||||
equal_pts(DecP, ecu_ed25519:decompress(CompP))
|
equal_pts(DecP, ecu_ed25519:decompress(CompP))
|
||||||
end).
|
end).
|
||||||
@@ -70,7 +70,7 @@ prop_generate_valid_point() ->
|
|||||||
prop_scalar_mul_base() ->
|
prop_scalar_mul_base() ->
|
||||||
?FORALL(S, gen_scalar(),
|
?FORALL(S, gen_scalar(),
|
||||||
begin
|
begin
|
||||||
E = enacl:crypto_ed25519_scalarmult_base(S),
|
E = enacl:curve25519_scalarmult_base(S),
|
||||||
P = ecu_ed25519:scalar_mul_base(S),
|
P = ecu_ed25519:scalar_mul_base(S),
|
||||||
equals(E, ecu_ed25519:compress(P))
|
equals(E, ecu_ed25519:compress(P))
|
||||||
end).
|
end).
|
||||||
@@ -78,7 +78,7 @@ prop_scalar_mul_base() ->
|
|||||||
prop_scalar_mul_base_noclamp() ->
|
prop_scalar_mul_base_noclamp() ->
|
||||||
?FORALL(S, gen_scalar(),
|
?FORALL(S, gen_scalar(),
|
||||||
begin
|
begin
|
||||||
E = enacl:crypto_ed25519_scalarmult_base_noclamp(S),
|
E = enacl:curve25519_scalarmult_base_noclamp(S),
|
||||||
P = ecu_ed25519:scalar_mul_base_noclamp(S),
|
P = ecu_ed25519:scalar_mul_base_noclamp(S),
|
||||||
equals(E, ecu_ed25519:compress(P))
|
equals(E, ecu_ed25519:compress(P))
|
||||||
end).
|
end).
|
||||||
@@ -86,7 +86,7 @@ prop_scalar_mul_base_noclamp() ->
|
|||||||
prop_scalar_mul() ->
|
prop_scalar_mul() ->
|
||||||
?FORALL({S, P0}, {gen_scalar(), gen_point()},
|
?FORALL({S, P0}, {gen_scalar(), gen_point()},
|
||||||
begin
|
begin
|
||||||
E = enacl:crypto_ed25519_scalarmult(S, P0),
|
E = enacl:curve25519_scalarmult(S, P0),
|
||||||
P = ecu_ed25519:scalar_mul(S, P0),
|
P = ecu_ed25519:scalar_mul(S, P0),
|
||||||
equals(E, ecu_ed25519:compress(P))
|
equals(E, ecu_ed25519:compress(P))
|
||||||
end).
|
end).
|
||||||
@@ -94,7 +94,7 @@ prop_scalar_mul() ->
|
|||||||
prop_scalar_mul_noclamp() ->
|
prop_scalar_mul_noclamp() ->
|
||||||
?FORALL({S, P0}, {gen_scalar(), gen_point()},
|
?FORALL({S, P0}, {gen_scalar(), gen_point()},
|
||||||
begin
|
begin
|
||||||
E = enacl:crypto_ed25519_scalarmult_noclamp(S, P0),
|
E = enacl:curve25519_scalarmult_noclamp(S, P0),
|
||||||
P = ecu_ed25519:scalar_mul_noclamp(S, ecu_ed25519:decompress(P0)),
|
P = ecu_ed25519:scalar_mul_noclamp(S, ecu_ed25519:decompress(P0)),
|
||||||
equals(E, ecu_ed25519:compress(P))
|
equals(E, ecu_ed25519:compress(P))
|
||||||
end).
|
end).
|
||||||
|
|||||||
+1
-1
@@ -20,7 +20,7 @@ gen_scalar() ->
|
|||||||
?LET(N, gen_large_n(), <<N:256/little>>).
|
?LET(N, gen_large_n(), <<N:256/little>>).
|
||||||
|
|
||||||
gen_point() ->
|
gen_point() ->
|
||||||
?LET(S, gen_scalar(), enacl:crypto_ed25519_scalarmult_base_noclamp(S)).
|
?LET(S, gen_scalar(), enacl:curve25519_scalarmult_base_noclamp(S)).
|
||||||
|
|
||||||
prop_keypair_seed() ->
|
prop_keypair_seed() ->
|
||||||
?FORALL(Seed, binary(32),
|
?FORALL(Seed, binary(32),
|
||||||
|
|||||||
+26
-8
@@ -1,13 +1,31 @@
|
|||||||
{erl_opts, [debug_info]}.
|
{erl_opts, [debug_info]}.
|
||||||
|
|
||||||
{plugins, [
|
{plugins, [{eqc_rebar, {git, "https://github.com/Quviq/eqc-rebar.git", {branch, "master"}}}]}.
|
||||||
{eqc_rebar, {git, "https://github.com/Quviq/eqc-rebar.git", {branch, "master"}}}
|
|
||||||
]}.
|
|
||||||
|
|
||||||
{deps,
|
{deps,
|
||||||
[{sha3, {git, "https://github.com/aeternity/erlang-sha3", {ref, "b5f27a2"}}}]}.
|
[{sha3,
|
||||||
|
{git,
|
||||||
|
"https://git.qpq.swiss/QPQ-AG/erlang-sha3.git",
|
||||||
|
{ref, "7290fa23664b4134d15da353061ac97aa158b332"}}}]}.
|
||||||
|
|
||||||
{profiles, [{test, [{deps, [{enacl, {git, "https://github.com/aeternity/enacl.git", {ref, "01dd0c2"}}},
|
{profiles,
|
||||||
{ecrecover, {git, "https://github.com/aeternity/ecrecover.git", {ref, "74b7816"}}}]}]},
|
[{test,
|
||||||
{eqc, [{deps, [{enacl, {git, "https://github.com/aeternity/enacl.git", {ref, "38ffc76"}}}]}]}
|
[{deps,
|
||||||
]}.
|
[{enacl,
|
||||||
|
{git,
|
||||||
|
"https://git.qpq.swiss/QPQ-AG/enacl.git",
|
||||||
|
{ref, "4eb7ec70084ba7c87b1af8797c4c4e90c84f95a2"}}},
|
||||||
|
{ecrecover,
|
||||||
|
{git,
|
||||||
|
"https://git.qpq.swiss/QPQ-AG/ecrecover.git",
|
||||||
|
{ref, "ce4175eaf2667a07ce41348dc6d4332477e30637"}}}]}]},
|
||||||
|
{eqc,
|
||||||
|
[{deps,
|
||||||
|
[{enacl,
|
||||||
|
{git,
|
||||||
|
"https://git.qpq.swiss/QPQ-AG/enacl.git",
|
||||||
|
{ref, "4eb7ec70084ba7c87b1af8797c4c4e90c84f95a2"}}},
|
||||||
|
{ecrecover,
|
||||||
|
{git,
|
||||||
|
"https://git.qpq.swiss/QPQ-AG/ecrecover.git",
|
||||||
|
{ref, "ce4175eaf2667a07ce41348dc6d4332477e30637"}}}]}]}]}.
|
||||||
|
|||||||
+4
-3
@@ -1,8 +1,9 @@
|
|||||||
{"1.2.0",
|
{"1.2.0",
|
||||||
[{<<"hex2bin">>,{pkg,<<"hex2bin">>,<<"1.0.0">>},1},
|
[{<<"hex2bin">>,{pkg,<<"hex2bin">>,<<"1.0.0">>},1},
|
||||||
{<<"sha3">>,
|
{<<"sha3">>,
|
||||||
{git,"https://github.com/aeternity/erlang-sha3",
|
{git,
|
||||||
{ref,"b5f27a29ba1179e5907c50d7ec7aa79b2857e981"}},
|
"https://git.qpq.swiss/QPQ-AG/erlang-sha3.git",
|
||||||
|
{ref, "7290fa23664b4134d15da353061ac97aa158b332"}},
|
||||||
0}]}.
|
0}]}.
|
||||||
[
|
[
|
||||||
{pkg_hash,[
|
{pkg_hash,[
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
-module(ec_utils).
|
-module(ec_utils).
|
||||||
-vsn("0.1.0").
|
-vsn("1.0.1").
|
||||||
|
|
||||||
-export([]).
|
-export([]).
|
||||||
|
|||||||
+31
-8
@@ -3,14 +3,16 @@
|
|||||||
%%% Description :
|
%%% Description :
|
||||||
%%% Created : 13 Jan 2022 by Hans Svensson
|
%%% Created : 13 Jan 2022 by Hans Svensson
|
||||||
-module(ecu_crypto).
|
-module(ecu_crypto).
|
||||||
-vsn("0.1.0").
|
-vsn("1.0.1").
|
||||||
|
|
||||||
-export([private_to_short/2, public_to_short/2,
|
-export([private_to_short/2, public_to_short/2,
|
||||||
eth_sign/2, eth_recover/2, eth_verify/3, eth_msg_hash/1,
|
ec_recover/2,
|
||||||
|
eth_sign/2, eth_recover/2, eth_verify/3,
|
||||||
|
eth_msg_sign/2, eth_msg_recover/2, eth_msg_verify/3, eth_msg_hash/1,
|
||||||
keccak256/1]).
|
keccak256/1]).
|
||||||
|
|
||||||
private_to_short(bitcoin, PrivateKey) ->
|
private_to_short(bitcoin, PrivateKey) ->
|
||||||
public_to_short(bitcoin, aeu_ecdsa:private_to_public(secp256k1, PrivateKey));
|
public_to_short(bitcoin, ecu_ecdsa:private_to_public(secp256k1, PrivateKey));
|
||||||
private_to_short(ethereum, <<PrivateKey:256>>) ->
|
private_to_short(ethereum, <<PrivateKey:256>>) ->
|
||||||
public_to_short(ethereum, ecu_secp256k1:scalar_mul_base(PrivateKey)).
|
public_to_short(ethereum, ecu_secp256k1:scalar_mul_base(PrivateKey)).
|
||||||
|
|
||||||
@@ -27,15 +29,33 @@ public_to_short(ethereum, PubKey) ->
|
|||||||
ShortPub
|
ShortPub
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
eth_msg_sign(Msg, PrivateKey = <<_:32/bytes>>) ->
|
||||||
|
eth_sign(eth_msg_hash(Msg), PrivateKey).
|
||||||
|
|
||||||
eth_sign(Msg, PrivateKey = <<_:32/bytes>>) ->
|
eth_sign(Msg, PrivateKey = <<_:32/bytes>>) ->
|
||||||
{BaseSig, YVal} = ecu_ecdsa:sign_secp256k1(eth_msg_hash(Msg), PrivateKey),
|
{BaseSig, YVal} = ecu_ecdsa:sign_secp256k1(Msg, PrivateKey),
|
||||||
V = if YVal rem 2 == 0 -> 27;
|
V = if YVal rem 2 == 0 -> 27;
|
||||||
true -> 28
|
true -> 28
|
||||||
end,
|
end,
|
||||||
<<V:8, BaseSig/bytes>>.
|
<<V:8, BaseSig/bytes>>.
|
||||||
|
|
||||||
eth_recover(Msg, Sig = <<_:65/bytes>>) ->
|
eth_msg_recover(Msg, Sig = <<_:65/bytes>>) ->
|
||||||
MsgHash = eth_msg_hash(Msg),
|
eth_recover(eth_msg_hash(Msg), Sig).
|
||||||
|
|
||||||
|
%% This is the mythical Ethereum ECRECOVERY operation
|
||||||
|
ec_recover(MsgHash = <<_:32/bytes>>, Sig = <<_:65/bytes>>) ->
|
||||||
|
<<V:8, R:256, S:256>> = Sig,
|
||||||
|
case (V == 27 orelse V == 28) andalso
|
||||||
|
(R >= 1 andalso R =< ecu_secp256k1:n()) andalso
|
||||||
|
(S >= 1 andalso S =< ecu_secp256k1:n()) of
|
||||||
|
true ->
|
||||||
|
ShortPub = eth_recover(MsgHash, Sig),
|
||||||
|
<<0:96, ShortPub/binary>>;
|
||||||
|
false ->
|
||||||
|
<<0:256>>
|
||||||
|
end.
|
||||||
|
|
||||||
|
eth_recover(MsgHash = <<_:32/bytes>>, Sig = <<_:65/bytes>>) ->
|
||||||
<<E:256>> = MsgHash,
|
<<E:256>> = MsgHash,
|
||||||
<<V:8, R:256, S:256>> = Sig,
|
<<V:8, R:256, S:256>> = Sig,
|
||||||
Z = E rem ecu_secp256k1:n(),
|
Z = E rem ecu_secp256k1:n(),
|
||||||
@@ -50,8 +70,11 @@ eth_recover(Msg, Sig = <<_:65/bytes>>) ->
|
|||||||
<<_:12/bytes, RPub:20/bytes>> = keccak256(<<X:256, Y:256>>),
|
<<_:12/bytes, RPub:20/bytes>> = keccak256(<<X:256, Y:256>>),
|
||||||
RPub.
|
RPub.
|
||||||
|
|
||||||
eth_verify(Msg, PublicKey, Sig) ->
|
eth_msg_verify(Msg, PublicKey, Sig) ->
|
||||||
PublicKey == eth_recover(Msg, Sig).
|
eth_verify(eth_msg_hash(Msg), PublicKey, Sig).
|
||||||
|
|
||||||
|
eth_verify(Msg, PublickKey, Sig) ->
|
||||||
|
PublickKey == eth_recover(Msg, Sig).
|
||||||
|
|
||||||
eth_msg_hash(Msg0) ->
|
eth_msg_hash(Msg0) ->
|
||||||
Msg = ["\x19Ethereum Signed Message:\n", integer_to_list(byte_size(Msg0)), Msg0],
|
Msg = ["\x19Ethereum Signed Message:\n", integer_to_list(byte_size(Msg0)), Msg0],
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
%%% Description : ecdsa functionality
|
%%% Description : ecdsa functionality
|
||||||
%%% Created : 13 Jan 2022 by Hans Svensson
|
%%% Created : 13 Jan 2022 by Hans Svensson
|
||||||
-module(ecu_ecdsa).
|
-module(ecu_ecdsa).
|
||||||
-vsn("0.1.0").
|
-vsn("1.0.1").
|
||||||
|
|
||||||
-export([sign/3, verify/4,
|
-export([sign/3, verify/4,
|
||||||
sign_secp256k1/2,
|
sign_secp256k1/2,
|
||||||
|
|||||||
+6
-4
@@ -4,7 +4,7 @@
|
|||||||
%%% Just for usage when speed isn't crucial...
|
%%% Just for usage when speed isn't crucial...
|
||||||
%%% Created : 13 Jan 2022 by Hans Svensson
|
%%% Created : 13 Jan 2022 by Hans Svensson
|
||||||
-module(ecu_ed25519).
|
-module(ecu_ed25519).
|
||||||
-vsn("0.1.0").
|
-vsn("1.0.1").
|
||||||
|
|
||||||
-define(P, 16#7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED).
|
-define(P, 16#7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED).
|
||||||
-define(N, 16#1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED).
|
-define(N, 16#1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED).
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
-type pt_affine() :: {non_neg_integer(), non_neg_integer()}. %% {X, Y}
|
-type pt_affine() :: {non_neg_integer(), non_neg_integer()}. %% {X, Y}
|
||||||
-type pt_hom_ext() :: {non_neg_integer(), non_neg_integer(),
|
-type pt_hom_ext() :: {non_neg_integer(), non_neg_integer(),
|
||||||
non_neg_integer(), non_neg_integer()}. %% {X, Y, Z, T}
|
non_neg_integer(), non_neg_integer()}. %% {X, Y, Z, T}
|
||||||
-type pt_compressed() :: <<_:32>>. %% Y coord + odd/even X.
|
-type pt_compressed() :: <<_:256>>. %% Y coord + odd/even X.
|
||||||
|
|
||||||
-type pt() :: pt_affine() | pt_hom_ext() | pt_compressed().
|
-type pt() :: pt_affine() | pt_hom_ext() | pt_compressed().
|
||||||
|
|
||||||
@@ -34,6 +34,8 @@
|
|||||||
-define(SUB(A, B), ((A - B + ?P) rem ?P)).
|
-define(SUB(A, B), ((A - B + ?P) rem ?P)).
|
||||||
-define(DIV(A, B), f_div(A, B)).
|
-define(DIV(A, B), f_div(A, B)).
|
||||||
|
|
||||||
|
-export_type([pt/0, scalar/0]).
|
||||||
|
|
||||||
-export([on_curve/1, p/0, n/0, pt_eq/2,
|
-export([on_curve/1, p/0, n/0, pt_eq/2,
|
||||||
scalar_mul/2, scalar_mul_base/1,
|
scalar_mul/2, scalar_mul_base/1,
|
||||||
scalar_mul_noclamp/2, scalar_mul_base_noclamp/1,
|
scalar_mul_noclamp/2, scalar_mul_base_noclamp/1,
|
||||||
@@ -77,14 +79,14 @@ n() -> ?N.
|
|||||||
|
|
||||||
-define(TWO_POW_255_MINUS_1, 16#7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF).
|
-define(TWO_POW_255_MINUS_1, 16#7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF).
|
||||||
|
|
||||||
-spec compress(P :: pt()) -> <<_:32>>.
|
-spec compress(P :: pt()) -> pt_compressed().
|
||||||
compress(<<_:32/binary>> = P) -> P;
|
compress(<<_:32/binary>> = P) -> P;
|
||||||
compress({_, _, _, _} = P) -> compress(to_affine(P));
|
compress({_, _, _, _} = P) -> compress(to_affine(P));
|
||||||
compress({X, Y}) ->
|
compress({X, Y}) ->
|
||||||
V = (Y band ?TWO_POW_255_MINUS_1) bor ((X band 1) bsl 255),
|
V = (Y band ?TWO_POW_255_MINUS_1) bor ((X band 1) bsl 255),
|
||||||
<<V:256/little>>.
|
<<V:256/little>>.
|
||||||
|
|
||||||
-spec decompress(<<_:32>>) -> pt_hom_ext().
|
-spec decompress(pt_compressed()) -> pt_hom_ext().
|
||||||
decompress(<<Y0:256/little>>) ->
|
decompress(<<Y0:256/little>>) ->
|
||||||
X0 = Y0 bsr 255,
|
X0 = Y0 bsr 255,
|
||||||
Y = Y0 band ?TWO_POW_255_MINUS_1,
|
Y = Y0 band ?TWO_POW_255_MINUS_1,
|
||||||
|
|||||||
+16
-17
@@ -3,7 +3,7 @@
|
|||||||
%%% Description : eddsa functionality - when possible compatible with enacl.
|
%%% Description : eddsa functionality - when possible compatible with enacl.
|
||||||
%%% Created : 19 Jan 2022 by Hans Svensson
|
%%% Created : 19 Jan 2022 by Hans Svensson
|
||||||
-module(ecu_eddsa).
|
-module(ecu_eddsa).
|
||||||
-vsn("0.1.0").
|
-vsn("1.0.1").
|
||||||
|
|
||||||
-export([sign_keypair/0,
|
-export([sign_keypair/0,
|
||||||
sign_seed_keypair/1,
|
sign_seed_keypair/1,
|
||||||
@@ -17,23 +17,22 @@
|
|||||||
%%
|
%%
|
||||||
%% The keypair is returned as a map with keys 'public' and 'secret'.
|
%% The keypair is returned as a map with keys 'public' and 'secret'.
|
||||||
%% @end
|
%% @end
|
||||||
-spec sign_keypair() -> #{ atom() => binary() }.
|
-spec sign_keypair() -> #{ public => binary(), secret => binary() }.
|
||||||
sign_keypair() ->
|
sign_keypair() ->
|
||||||
Secret = crypto:strong_rand_bytes(32),
|
Secret = crypto:strong_rand_bytes(32),
|
||||||
<<Seed:32/bytes, _/binary>> = crypto:hash(sha512, Secret),
|
<<Seed:32/binary, _/binary>> = crypto:hash(sha512, Secret),
|
||||||
|
|
||||||
Pub = ecu_ed25519:scalar_mul_base(Seed),
|
Pub = ecu_ed25519:compress(ecu_ed25519:scalar_mul_base(Seed)),
|
||||||
#{public => Pub, secret => <<Secret:32/binary, Pub:32/binary>>}.
|
#{public => Pub, secret => <<Secret:32/binary, Pub:32/binary>>}.
|
||||||
|
|
||||||
%% @doc sign_seed_keypair/1 computes the signing keypair from a seed.
|
%% @doc sign_seed_keypair/1 computes the signing keypair from a seed.
|
||||||
%%
|
%%
|
||||||
%% The keypair is returned as a map with keys 'public' and 'secret'.
|
%% The keypair is returned as a map with keys 'public' and 'secret'.
|
||||||
%% @end
|
%% @end
|
||||||
-spec sign_seed_keypair(Seed :: <<_:32>>) -> #{ atom() => binary() }.
|
-spec sign_seed_keypair(Secret :: <<_:256>>) -> #{ public => binary(), secret => binary() }.
|
||||||
sign_seed_keypair(Secret) ->
|
sign_seed_keypair(Secret) ->
|
||||||
<<Seed:32/bytes, _/binary>> = crypto:hash(sha512, Secret),
|
<<Seed:32/binary, _/binary>> = crypto:hash(sha512, Secret),
|
||||||
Pub = ecu_ed25519:compress(ecu_ed25519:scalar_mul_base(Seed)),
|
Pub = ecu_ed25519:compress(ecu_ed25519:scalar_mul_base(Seed)),
|
||||||
%% Pub = enacl:crypto_ed25519_scalarmult_base(Seed),
|
|
||||||
|
|
||||||
#{public => Pub, secret => <<Secret:32/binary, Pub:32/binary>>}.
|
#{public => Pub, secret => <<Secret:32/binary, Pub:32/binary>>}.
|
||||||
|
|
||||||
@@ -42,7 +41,7 @@ sign_seed_keypair(Secret) ->
|
|||||||
%% Given a message `Msg' and a secret key `SK' the function will sign the
|
%% Given a message `Msg' and a secret key `SK' the function will sign the
|
||||||
%% message and return a signed message `SM'.
|
%% message and return a signed message `SM'.
|
||||||
%% @end
|
%% @end
|
||||||
-spec sign(Msg :: iodata(), SK :: <<_:32>> | <<_:64>>) -> SM :: binary().
|
-spec sign(Msg :: iodata(), SK :: <<_:256>> | <<_:512>>) -> SM :: binary().
|
||||||
sign(Msg, SK) ->
|
sign(Msg, SK) ->
|
||||||
BinMsg = iolist_to_binary(Msg),
|
BinMsg = iolist_to_binary(Msg),
|
||||||
Sig = sign_detached(Msg, SK),
|
Sig = sign_detached(Msg, SK),
|
||||||
@@ -55,12 +54,12 @@ sign(Msg, SK) ->
|
|||||||
%% `{error, failed_verification}' depending on the correctness of the
|
%% `{error, failed_verification}' depending on the correctness of the
|
||||||
%% signature.
|
%% signature.
|
||||||
%% @end
|
%% @end
|
||||||
-spec sign_open(SMsg :: binary(), PK :: <<_:32>>) ->
|
-spec sign_open(SMsg :: binary(), PK :: <<_:256>>) ->
|
||||||
{ok, Msg :: binary()} | {error, failed_verification}.
|
{ok, Msg :: binary()} | {error, failed_verification}.
|
||||||
sign_open(<<Sig:64/binary, BinMsg/binary>>, PK) ->
|
sign_open(<<Sig:64/binary, BinMsg/binary>>, PK) ->
|
||||||
<<R:32/bytes, Ss:32/bytes>> = Sig,
|
<<R:32/binary, Ss:32/binary>> = Sig,
|
||||||
|
|
||||||
Ks0 = crypto:hash(sha512, <<R/bytes, PK/bytes, BinMsg/bytes>>),
|
Ks0 = crypto:hash(sha512, <<R/binary, PK/binary, BinMsg/binary>>),
|
||||||
Ks = ecu_ed25519:scalar_reduce(Ks0),
|
Ks = ecu_ed25519:scalar_reduce(Ks0),
|
||||||
|
|
||||||
LHS = ecu_ed25519:scalar_mul_base_noclamp(Ss),
|
LHS = ecu_ed25519:scalar_mul_base_noclamp(Ss),
|
||||||
@@ -78,7 +77,7 @@ sign_open(<<Sig:64/binary, BinMsg/binary>>, PK) ->
|
|||||||
%% Given a message `Msg' and a secret key `SK' the function will compute the
|
%% Given a message `Msg' and a secret key `SK' the function will compute the
|
||||||
%% digital signature `Sig'.
|
%% digital signature `Sig'.
|
||||||
%% @end
|
%% @end
|
||||||
-spec sign_detached(Msg :: iodata(), SK :: <<_:32>>) -> Sig :: binary().
|
-spec sign_detached(Msg :: iodata(), SK :: <<_:256>> | <<_:512>>) -> Sig :: binary().
|
||||||
sign_detached(Msg, SK) ->
|
sign_detached(Msg, SK) ->
|
||||||
BinMsg = iolist_to_binary(Msg),
|
BinMsg = iolist_to_binary(Msg),
|
||||||
<<Secret:32/binary, _/binary>> = SK,
|
<<Secret:32/binary, _/binary>> = SK,
|
||||||
@@ -120,12 +119,12 @@ sign_detached(Msg, SK) ->
|
|||||||
%% function computes true iff the `Sig' is valid for `Msg' and `PK'; and,
|
%% function computes true iff the `Sig' is valid for `Msg' and `PK'; and,
|
||||||
%% false otherwise.
|
%% false otherwise.
|
||||||
%% @end
|
%% @end
|
||||||
-spec sign_verify_detached(Sig :: <<_:64>>, Msg :: iodata(), PK :: <<_:32>>) -> boolean().
|
-spec sign_verify_detached(Sig :: <<_:512>>, Msg :: iodata(), PK :: <<_:256>>) -> boolean().
|
||||||
sign_verify_detached(Sig, Msg, PK) ->
|
sign_verify_detached(Sig, Msg, PK) ->
|
||||||
BinMsg = iolist_to_binary(Msg),
|
BinMsg = iolist_to_binary(Msg),
|
||||||
<<R:32/bytes, Ss:32/bytes>> = Sig,
|
<<R:32/binary, Ss:32/binary>> = Sig,
|
||||||
|
|
||||||
Ks0 = crypto:hash(sha512, <<R/bytes, PK/bytes, BinMsg/bytes>>),
|
Ks0 = crypto:hash(sha512, <<R/binary, PK/binary, BinMsg/binary>>),
|
||||||
Ks = ecu_ed25519:scalar_reduce(Ks0),
|
Ks = ecu_ed25519:scalar_reduce(Ks0),
|
||||||
|
|
||||||
LHS = ecu_ed25519:scalar_mul_base_noclamp(Ss),
|
LHS = ecu_ed25519:scalar_mul_base_noclamp(Ss),
|
||||||
@@ -137,5 +136,5 @@ sign_verify_detached(Sig, Msg, PK) ->
|
|||||||
%% Clamp a 32-byte little-endian integer - i.e clear the lowest three bits
|
%% Clamp a 32-byte little-endian integer - i.e clear the lowest three bits
|
||||||
%% of the first byte and clear the highest and set the second highest of
|
%% of the first byte and clear the highest and set the second highest of
|
||||||
%% the last byte (i.e. making it divisible by 8 and
|
%% the last byte (i.e. making it divisible by 8 and
|
||||||
clamp(<<B0:8, B1_30:30/bytes, B31:8>>) ->
|
clamp(<<B0:8, B1_30:30/binary, B31:8>>) ->
|
||||||
<<(B0 band 16#f8):8, B1_30/bytes, ((B31 band 16#7f) bor 16#40):8>>.
|
<<(B0 band 16#f8):8, B1_30/binary, ((B31 band 16#7f) bor 16#40):8>>.
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
%%% Description : Misc. functionality
|
%%% Description : Misc. functionality
|
||||||
%%% Created : 13 Jan 2022 by Hans Svensson
|
%%% Created : 13 Jan 2022 by Hans Svensson
|
||||||
-module(ecu_misc).
|
-module(ecu_misc).
|
||||||
-vsn("0.1.0").
|
-vsn("1.0.1").
|
||||||
|
|
||||||
-export([eea/2, exp_mod/3,
|
-export([eea/2, exp_mod/3,
|
||||||
hex_to_bin/1, bin_to_hex/1,
|
hex_to_bin/1, bin_to_hex/1,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
%%% Just for usage when speed isn't crucial...
|
%%% Just for usage when speed isn't crucial...
|
||||||
%%% Created : 22 Dec 2021 by Hans Svensson
|
%%% Created : 22 Dec 2021 by Hans Svensson
|
||||||
-module(ecu_secp256k1).
|
-module(ecu_secp256k1).
|
||||||
-vsn("0.1.0").
|
-vsn("1.0.1").
|
||||||
|
|
||||||
-define(P, 16#FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F).
|
-define(P, 16#FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F).
|
||||||
-define(A, 16#00).
|
-define(A, 16#00).
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ gen_scalar() ->
|
|||||||
1 + X rem (ecu_ed25519:n() - 1).
|
1 + X rem (ecu_ed25519:n() - 1).
|
||||||
|
|
||||||
bench_point_add_test() ->
|
bench_point_add_test() ->
|
||||||
Pts = [ enacl:crypto_ed25519_scalarmult_base(<<(gen_scalar()):256/little>>) || _ <- lists:seq(1, 100) ],
|
Pts = [ enacl:curve25519_scalarmult_base(<<(gen_scalar()):256/little>>) || _ <- lists:seq(1, 100) ],
|
||||||
|
|
||||||
PtsEnacl0 = lists:zip(Pts, tl(Pts) ++ [hd(Pts)]),
|
PtsEnacl0 = lists:zip(Pts, tl(Pts) ++ [hd(Pts)]),
|
||||||
PtsEd255190 = [ {ecu_ed25519:to_ext_hom(P1), ecu_ed25519:to_ext_hom(P2)} || {P1, P2} <- lists:zip(Pts, tl(Pts) ++ [hd(Pts)]) ],
|
PtsEd255190 = [ {ecu_ed25519:to_ext_hom(P1), ecu_ed25519:to_ext_hom(P2)} || {P1, P2} <- lists:zip(Pts, tl(Pts) ++ [hd(Pts)]) ],
|
||||||
@@ -39,7 +39,7 @@ bench_scalar_mul_base_test() ->
|
|||||||
ScalarsEd25519 = lists:append(lists:duplicate(30, Scalars0)),
|
ScalarsEd25519 = lists:append(lists:duplicate(30, Scalars0)),
|
||||||
|
|
||||||
{TimeSecp, _} = timer:tc(fun() -> [ecu_secp256k1:scalar_mul_base(S) || S <- ScalarsSecp], ok end),
|
{TimeSecp, _} = timer:tc(fun() -> [ecu_secp256k1:scalar_mul_base(S) || S <- ScalarsSecp], ok end),
|
||||||
{TimeEnacl, _} = timer:tc(fun() -> [enacl:crypto_ed25519_scalarmult_base(S) || S <- ScalarsEnacl], ok end),
|
{TimeEnacl, _} = timer:tc(fun() -> [enacl:curve25519_scalarmult_base(S) || S <- ScalarsEnacl], ok end),
|
||||||
{TimeEd25519, _} = timer:tc(fun() -> [ecu_ed25519:scalar_mul_base(S) || S <- ScalarsEd25519], ok end),
|
{TimeEd25519, _} = timer:tc(fun() -> [ecu_ed25519:scalar_mul_base(S) || S <- ScalarsEd25519], ok end),
|
||||||
|
|
||||||
?debugFmt("", []),
|
?debugFmt("", []),
|
||||||
@@ -58,7 +58,7 @@ bench_scalar_mul_test() ->
|
|||||||
Test = fun(F, P0, Ss) -> lists:foldl(fun(S, P) -> F(S, P) end, P0, Ss) end,
|
Test = fun(F, P0, Ss) -> lists:foldl(fun(S, P) -> F(S, P) end, P0, Ss) end,
|
||||||
|
|
||||||
{TimeSecp, _} = timer:tc(fun() -> Test(fun ecu_secp256k1:scalar_mul/2, ecu_secp256k1:scalar_mul_base(hd(ScalarsSecp)), tl(ScalarsSecp)) end),
|
{TimeSecp, _} = timer:tc(fun() -> Test(fun ecu_secp256k1:scalar_mul/2, ecu_secp256k1:scalar_mul_base(hd(ScalarsSecp)), tl(ScalarsSecp)) end),
|
||||||
{TimeEnacl, _} = timer:tc(fun() -> Test(fun enacl:crypto_ed25519_scalarmult/2, enacl:crypto_ed25519_scalarmult_base(hd(ScalarsEnacl)), tl(ScalarsEnacl)) end),
|
{TimeEnacl, _} = timer:tc(fun() -> Test(fun enacl:curve25519_scalarmult/2, enacl:curve25519_scalarmult_base(hd(ScalarsEnacl)), tl(ScalarsEnacl)) end),
|
||||||
{TimeEd25519, _} = timer:tc(fun() -> Test(fun ecu_ed25519:scalar_mul/2, ecu_ed25519:scalar_mul_base(hd(ScalarsEd25519)), tl(ScalarsEd25519)) end),
|
{TimeEd25519, _} = timer:tc(fun() -> Test(fun ecu_ed25519:scalar_mul/2, ecu_ed25519:scalar_mul_base(hd(ScalarsEd25519)), tl(ScalarsEd25519)) end),
|
||||||
|
|
||||||
?debugFmt("", []),
|
?debugFmt("", []),
|
||||||
|
|||||||
@@ -20,16 +20,16 @@ eth_sign_verify_test() ->
|
|||||||
Data = [{Pr, ecu_crypto:private_to_short(ethereum, Pr), M} || {Pr, M} <- Data0],
|
Data = [{Pr, ecu_crypto:private_to_short(ethereum, Pr), M} || {Pr, M} <- Data0],
|
||||||
|
|
||||||
Test = fun(PrivK, PubK, MsgHash) ->
|
Test = fun(PrivK, PubK, MsgHash) ->
|
||||||
Sig = ecu_crypto:eth_sign(MsgHash, PrivK),
|
Sig = ecu_crypto:eth_msg_sign(MsgHash, PrivK),
|
||||||
?assertEqual(PubK, ecu_crypto:eth_recover(MsgHash, Sig))
|
?assertEqual(PubK, ecu_crypto:eth_msg_recover(MsgHash, Sig))
|
||||||
end,
|
end,
|
||||||
|
|
||||||
{T, _} = timer:tc(fun() -> [ Test(Pr, Pu, M) || {Pr, Pu, M} <- Data ] end),
|
{T, _} = timer:tc(fun() -> [ Test(Pr, Pu, M) || {Pr, Pu, M} <- Data ] end),
|
||||||
?debugFmt("Average time for eth_sign+eth_recovery: ~.3f ms", [(T / 1000) / length(Data)]).
|
?debugFmt("Average time for eth_msg_sign+eth_msg_recovery: ~.3f ms", [(T / 1000) / length(Data)]).
|
||||||
|
|
||||||
recover_test() ->
|
recover_test() ->
|
||||||
<<R:256, S:256>> = ecu_misc:hex_to_bin("a5f270865420c8595128cf7132dcedb1221abf89286f926d067dff2fa59347c07a0fd06e8b4a567b0628a01d5398480a49c540c0cbd9980abd08cf3818f25e2e"),
|
<<R:256, S:256>> = ecu_misc:hex_to_bin("a5f270865420c8595128cf7132dcedb1221abf89286f926d067dff2fa59347c07a0fd06e8b4a567b0628a01d5398480a49c540c0cbd9980abd08cf3818f25e2e"),
|
||||||
%% <<Priv:256>> = hex_to_bin("9a4a5c038e7ce00f0ad216894afc00de6b41bbca1d4d7742104cb9f078c6d2df"),
|
%% <<Priv:256>> = hex_to_bin("9a4a5c038e7ce00f0ad216894afc00de6b41bbca1d4d7742104cb9f078c6d2df"),
|
||||||
%% <<Z:256>> = hex_to_bin("4a5c5d454721bbbb25540c3317521e71c373ae36458f960d2ad46ef088110e95"), %% MsgHash
|
%% <<Z:256>> = hex_to_bin("4a5c5d454721bbbb25540c3317521e71c373ae36458f960d2ad46ef088110e95"), %% MsgHash
|
||||||
ShortPub = ecu_misc:hex_to_bin("E53e2125F377D5c62a1FfbfEEB89A0826E9dE54C"),
|
ShortPub = ecu_misc:hex_to_bin("E53e2125F377D5c62a1FfbfEEB89A0826E9dE54C"),
|
||||||
?assertEqual(ShortPub, ecu_crypto:eth_recover(<<"test">>, <<28:8, R:256, S:256>>)).
|
?assertEqual(ShortPub, ecu_crypto:eth_msg_recover(<<"test">>, <<28:8, R:256, S:256>>)).
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
{a_email,"zxq9@zxq9.com"}.
|
|
||||||
{author,"Craig Everett"}.
|
|
||||||
{c_email,[]}.
|
|
||||||
{copyright,"Hans Svensson"}.
|
|
||||||
{deps,[]}.
|
|
||||||
{desc,"Helper functions for cryptography, mostly related to elliptic curves."}.
|
|
||||||
{file_exts,[]}.
|
|
||||||
{key_name,none}.
|
|
||||||
{license,"MIT"}.
|
|
||||||
{modules,[]}.
|
|
||||||
{name,"Elliptic Curve Utils"}.
|
{name,"Elliptic Curve Utils"}.
|
||||||
{package_id,{"otpr","ec_utils",{0,1,0}}}.
|
|
||||||
{prefix,none}.
|
|
||||||
{repo_url,"https://github.com/zxq9/ec_utils"}.
|
|
||||||
{tags,[]}.
|
|
||||||
{type,lib}.
|
{type,lib}.
|
||||||
{ws_url,"https://github.com/hanssv/ec_utils"}.
|
{modules,[]}.
|
||||||
|
{prefix,none}.
|
||||||
|
{desc,"Helper functions for cryptography, mostly related to elliptic curves."}.
|
||||||
|
{author,"Hans Svensson"}.
|
||||||
|
{package_id,{"otpr","ec_utils",{1,0,1}}}.
|
||||||
|
{deps,[{"otpr","sha3",{0,1,5}}]}.
|
||||||
|
{key_name,none}.
|
||||||
|
{a_email,"hanssv@gmail.com"}.
|
||||||
|
{c_email,"hanssv@gmail.com"}.
|
||||||
|
{copyright,"Hans Svensson"}.
|
||||||
|
{file_exts,[]}.
|
||||||
|
{license,"MIT"}.
|
||||||
|
{repo_url,"https://git.qpq.swiss/QPQ-AG/ec_utils"}.
|
||||||
|
{tags,["cryptography","elliptic curve","crypto","enacl"]}.
|
||||||
|
{ws_url,"https://git.qpq.swiss/QPQ-AG/ec_utils"}.
|
||||||
|
|||||||
Reference in New Issue
Block a user