diff --git a/eqc_test/enacl_eqc.erl b/eqc_test/enacl_eqc.erl index b1aa1d6..bb6eae3 100644 --- a/eqc_test/enacl_eqc.erl +++ b/eqc_test/enacl_eqc.erl @@ -115,6 +115,73 @@ prop_box_failure_integrity() -> end end). +%% SIGNATURES +%% ---------- + +prop_sign_keypair() -> + ?FORALL(_D, return(dummy), + begin + #{ public := _, secret := _ } = enacl:sign_keypair(), + true + end). + +sign_keypair_bad() -> + ?LET(X, elements([pk, sk]), + begin + KP = enacl:sign_keypair(), + case X of + pk -> + Sz = enacl:sign_keypair_public_size(), + ?LET(Wrong, oneof([a, int(), ?SUCHTHAT(B, binary(), byte_size(B) /= Sz)]), + KP#{ public := Wrong }); + sk -> + Sz = enacl:sign_keypair_secret_size(), + ?LET(Wrong, oneof([a, int(), ?SUCHTHAT(B, binary(), byte_size(B) /= Sz)]), + KP#{ secret := Wrong }) + end + end). + +sign_keypair_good() -> + return(enacl:sign_keypair()). + +sign_keypair() -> + fault(sign_keypair_bad(), sign_keypair_good()). + +sign_keypair_public_valid(#{ public := Public }) + when is_binary(Public) -> + byte_size(Public) == enacl:sign_keypair_public_size(); +sign_keypair_public_valid(_) -> false. + +sign_keypair_secret_valid(#{ secret := Secret }) + when is_binary(Secret) -> + byte_size(Secret) == enacl:sign_keypair_secret_size(); +sign_keypair_secret_valid(_) -> false. + +sign_keypair_valid(KP) -> + sign_keypair_public_valid(KP) andalso sign_keypair_secret_valid(KP). + +prop_sign() -> + ?FORALL({Msg, KeyPair}, {binary(), fault_rate(1, 40, sign_keypair())}, + begin + case sign_keypair_secret_valid(KeyPair) of + true -> + #{ secret := Secret } = KeyPair, + enacl:sign(Msg, Secret), + true; + false -> + #{ secret := Secret } = KeyPair, + badargs(fun() -> enacl:sign(Msg, Secret) end) + end + end). + +prop_sign_open() -> + ?FORALL({Msg, KeyPair}, {binary(), sign_keypair()}, + begin + #{ public := Public, secret := Secret } = KeyPair, + SM = enacl:sign(Msg, Secret), + equals({ok, Msg}, enacl:sign_open(SM, Public)) + end). + %% CRYPTO SECRET BOX %% ------------------------------- diff --git a/src/enacl.erl b/src/enacl.erl index 64c785e..58c778c 100644 --- a/src/enacl.erl +++ b/src/enacl.erl @@ -25,6 +25,8 @@ box_public_key_bytes/0, box_secret_key_bytes/0, + sign_keypair_public_size/0, + sign_keypair_secret_size/0, sign_keypair/0, sign/2, sign_open/2 @@ -147,13 +149,21 @@ box_public_key_bytes() -> %% Signatures +%% @private +sign_keypair_public_size() -> + enacl_nif:crypto_sign_PUBLICKEYBYTES(). + +%% @private +sign_keypair_secret_size() -> + enacl_nif:crypto_sign_SECRETKEYBYTES(). + %% @doc sign_keypair/0 returns a signature keypair for signing %% The returned value is a map in order to make it harder to misuse keys. %% @end -spec sign_keypair() -> KeyMap when KeyMap :: maps:map(atom(), binary()). sign_keypair() -> - {PK, SK} = enacl_nif:sign_keypair(), + {PK, SK} = enacl_nif:crypto_sign_keypair(), #{ public => PK, secret => SK}. %% @doc sign/2 signs a message with a digital signature identified by a secret key. @@ -164,7 +174,7 @@ sign_keypair() -> M :: binary(), SK :: binary(), SM :: binary(). -sign(M, SK) -> enacl_nif:sign(M, SK). +sign(M, SK) -> enacl_nif:crypto_sign(M, SK). %% @doc sign_open/2 opens a digital signature %% Given a signed message `SM' and a public key `PK', verify that the message has the right signature. Returns either @@ -175,7 +185,11 @@ sign(M, SK) -> enacl_nif:sign(M, SK). SM :: binary(), PK :: binary(), M :: binary(). -sign_open(SM, PK) -> enacl_nif:sign_open(SM, PK). +sign_open(SM, PK) -> + case enacl_nif:crypto_sign_open(SM, PK) of + M when is_binary(M) -> {ok, M}; + {error, Err} -> {error, Err} + end. %% @private -spec box_secret_key_bytes() -> pos_integer().