Add some EcDSA functionality
This commit is contained in:
parent
247f726f0d
commit
06f0f0aa79
@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
### Added
|
### Added
|
||||||
- Basic operations (scalar arithmetics, point addition, scalar multiplication)
|
- Basic operations (scalar arithmetics, point addition, scalar multiplication)
|
||||||
for secp256k1 in pure Erlang code
|
for secp256k1 in pure Erlang code
|
||||||
|
- ecdsa sign/verify
|
||||||
|
|
||||||
|
|
||||||
[Unreleased]: https://github.com/hanssv/ec_utils/compare/v0.1.0...HEAD
|
[Unreleased]: https://github.com/hanssv/ec_utils/compare/v0.1.0...HEAD
|
||||||
|
53
src/ecu_ecdsa.erl
Normal file
53
src/ecu_ecdsa.erl
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
%%% File : ecu_ecdsa.erl
|
||||||
|
%%% Author : Hans Svensson
|
||||||
|
%%% Description : ecdsa functionality
|
||||||
|
%%% Created : 13 Jan 2022 by Hans Svensson
|
||||||
|
-module(ecu_ecdsa).
|
||||||
|
|
||||||
|
-export([sign/3, verify/4,
|
||||||
|
sign_secp256k1/2,
|
||||||
|
private_to_public/2]).
|
||||||
|
|
||||||
|
private_to_public(secp256k1, <<PrivateKey:256>>) ->
|
||||||
|
ecu_secp256k1:compress(ecu_secp256k1:scalar_mul_base(PrivateKey)).
|
||||||
|
|
||||||
|
sign(secp256k1, MsgHash = <<_:32/bytes>>, PrivateKey = <<_:32/bytes>>) ->
|
||||||
|
{Sig, _YVal} = sign_secp256k1(MsgHash, PrivateKey),
|
||||||
|
Sig.
|
||||||
|
|
||||||
|
verify(secp256k1, MsgHash = <<_:32/bytes>>, PubKey = <<_:33/bytes>>, Sig = <<_:64/bytes>>) ->
|
||||||
|
verify(secp256k1, MsgHash, ecu_secp256k1:decompress(PubKey), Sig);
|
||||||
|
verify(secp256k1, MsgHash = <<_:32/bytes>>, PubKey = {_, _}, Sig = <<_:64/bytes>>) ->
|
||||||
|
<<E:256>> = MsgHash,
|
||||||
|
<<R:256, S:256>> = Sig,
|
||||||
|
Z = E rem ecu_secp256k1:n(),
|
||||||
|
W = ecu_secp256k1:s_inv(S),
|
||||||
|
[P1, P2] = ecu_misc:pcomp(
|
||||||
|
[fun() -> ecu_secp256k1:scalar_mul_base(ecu_secp256k1:s_mul(Z, W)) end,
|
||||||
|
fun() -> ecu_secp256k1:scalar_mul(ecu_secp256k1:s_mul(R, W), PubKey) end]),
|
||||||
|
{X, _Y} = ecu_secp256k1:p_add(P1, P2),
|
||||||
|
R == (X rem ecu_secp256k1:n()).
|
||||||
|
|
||||||
|
sign_secp256k1(MsgHash = <<_:32/bytes>>, PrivateKey = <<_:32/bytes>>) ->
|
||||||
|
<<E:256>> = MsgHash,
|
||||||
|
<<D:256>> = PrivateKey,
|
||||||
|
Z = E rem ecu_secp256k1:n(),
|
||||||
|
K = pick_k(secp256k1),
|
||||||
|
{X, Y} = ecu_secp256k1:scalar_mul_base(K),
|
||||||
|
R = X rem ecu_secp256k1:n(),
|
||||||
|
S = ecu_secp256k1:s_mul(ecu_secp256k1:s_inv(K),
|
||||||
|
ecu_secp256k1:s_add(Z, ecu_secp256k1:s_mul(R, D))),
|
||||||
|
if R == 0 orelse S == 0 ->
|
||||||
|
sign(secp256k1, MsgHash, PrivateKey);
|
||||||
|
true ->
|
||||||
|
{<<R:256, S:256>>, Y}
|
||||||
|
end.
|
||||||
|
|
||||||
|
%% --- internal functions
|
||||||
|
|
||||||
|
pick_k(secp256k1) ->
|
||||||
|
<<K:256>> = crypto:strong_rand_bytes(32),
|
||||||
|
case K == 0 orelse K >= ecu_secp256k1:n() of
|
||||||
|
true -> pick_k(secp256k1);
|
||||||
|
false -> K
|
||||||
|
end.
|
@ -4,7 +4,7 @@
|
|||||||
%%% Created : 13 Jan 2022 by Hans Svensson
|
%%% Created : 13 Jan 2022 by Hans Svensson
|
||||||
-module(ecu_misc).
|
-module(ecu_misc).
|
||||||
|
|
||||||
-export([eea/2]).
|
-export([eea/2, pcomp/1]).
|
||||||
|
|
||||||
%% Extended Euclidean Algorithm
|
%% Extended Euclidean Algorithm
|
||||||
eea(A, B) when ((A < 1) or (B < 1)) ->
|
eea(A, B) when ((A < 1) or (B < 1)) ->
|
||||||
@ -18,4 +18,8 @@ eea(G0, S0, T0, G1, S1, T1) ->
|
|||||||
Q = G0 div G1,
|
Q = G0 div G1,
|
||||||
eea(G1, S1, T1, G0 - (Q * G1), S0 - (Q * S1), T0 - (Q * T1)).
|
eea(G1, S1, T1, G0 - (Q * G1), S0 - (Q * S1), T0 - (Q * T1)).
|
||||||
|
|
||||||
|
%% Very rudimentary parallel computation...
|
||||||
|
pcomp(Fs) ->
|
||||||
|
Parent = self(),
|
||||||
|
Pids = [ spawn(fun() -> Parent ! {self(), F()} end) || F <- Fs ],
|
||||||
|
[ receive {Pid, X} -> X after 500 -> error(timeout) end || Pid <- Pids ].
|
||||||
|
27
test/ecdsa_tests.erl
Normal file
27
test/ecdsa_tests.erl
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
%%% File : ecdsa_tests.erl
|
||||||
|
%%% Author : Hans Svensson
|
||||||
|
%%% Description :
|
||||||
|
%%% Created : 12 Jan 2022 by Hans Svensson
|
||||||
|
-module(ecdsa_tests).
|
||||||
|
|
||||||
|
-compile([export_all, nowarn_export_all]).
|
||||||
|
|
||||||
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
|
gen_ecdsa_secp256k1_privkey() ->
|
||||||
|
<<P0:256>> = crypto:strong_rand_bytes(32),
|
||||||
|
P = (P0 rem (ecu_secp256k1:n() - 1)) + 1,
|
||||||
|
<<P:256>>.
|
||||||
|
|
||||||
|
ecdsa_sign_verify_secp256k1_test() ->
|
||||||
|
Data0 = [ {gen_ecdsa_secp256k1_privkey(), crypto:strong_rand_bytes(32)} || _ <- lists:seq(1, 10) ],
|
||||||
|
|
||||||
|
Data = [{Pr, ecu_ecdsa:private_to_public(secp256k1, Pr), M} || {Pr, M} <- Data0],
|
||||||
|
|
||||||
|
Test = fun(PrivK, PubK, MsgHash) ->
|
||||||
|
Sig = ecu_ecdsa:sign(secp256k1, MsgHash, PrivK),
|
||||||
|
?assert(ecu_ecdsa:verify(secp256k1, MsgHash, PubK, Sig))
|
||||||
|
end,
|
||||||
|
|
||||||
|
{T, _} = timer:tc(fun() -> [ Test(Pr, Pu, M) || {Pr, Pu, M} <- Data ] end),
|
||||||
|
?debugFmt("Average time for sign+verify: ~.3f ms", [(T / 1000) / length(Data)]).
|
Loading…
x
Reference in New Issue
Block a user