[PT-167805291] Add opcode for ecrecover (#122)
* Add opcode for ecrecover * Update aebytecode * Extend signature bytes type used for ecrecover * Add ecrecover to changelog * Add some type specs * Please dialyzer
This commit is contained in:
parent
b669d2df1e
commit
dd26649f7d
@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Added
|
### Added
|
||||||
|
- New builtin function `Crypto.ecrecover_secp256k1: (hash, bytes(65)) => bytes(32)`
|
||||||
|
for recovering Ethereum address from message hash and signature.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- New syntax for tuple types. Now 0-tuple type is encoded as `unit` instead of `()` and
|
- New syntax for tuple types. Now 0-tuple type is encoded as `unit` instead of `()` and
|
||||||
regular tuples are encoded by interspersing inner types with `*`, for instance `int * string`.
|
regular tuples are encoded by interspersing inner types with `*`, for instance `int * string`.
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
{erl_opts, [debug_info]}.
|
{erl_opts, [debug_info]}.
|
||||||
|
|
||||||
{deps, [ {aebytecode, {git, "https://github.com/aeternity/aebytecode.git", {ref,"af6224c"}}}
|
{deps, [ {aebytecode, {git, "https://github.com/aeternity/aebytecode.git", {ref,"3954bd2"}}}
|
||||||
, {getopt, "1.0.1"}
|
, {getopt, "1.0.1"}
|
||||||
, {eblake2, "1.0.0"}
|
, {eblake2, "1.0.0"}
|
||||||
, {jsx, {git, "https://github.com/talentdeficit/jsx.git",
|
, {jsx, {git, "https://github.com/talentdeficit/jsx.git",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{"1.1.0",
|
{"1.1.0",
|
||||||
[{<<"aebytecode">>,
|
[{<<"aebytecode">>,
|
||||||
{git,"https://github.com/aeternity/aebytecode.git",
|
{git,"https://github.com/aeternity/aebytecode.git",
|
||||||
{ref,"af6224cb3b3732562df58485b2bd2a0534d74f2a"}},
|
{ref,"3954bd22daa24d4a82a8349325d115cd7b7d1750"}},
|
||||||
0},
|
0},
|
||||||
{<<"aeserialization">>,
|
{<<"aeserialization">>,
|
||||||
{git,"https://github.com/aeternity/aeserialization.git",
|
{git,"https://github.com/aeternity/aeserialization.git",
|
||||||
|
@ -83,7 +83,7 @@
|
|||||||
|
|
||||||
-type fun_info() :: {aeso_syntax:ann(), typesig() | type()}.
|
-type fun_info() :: {aeso_syntax:ann(), typesig() | type()}.
|
||||||
-type type_info() :: {aeso_syntax:ann(), typedef()}.
|
-type type_info() :: {aeso_syntax:ann(), typedef()}.
|
||||||
-type var_info() :: {aeso_syntax:ann(), type()}.
|
-type var_info() :: {aeso_syntax:ann(), utype()}.
|
||||||
|
|
||||||
-type fun_env() :: [{name(), fun_info()}].
|
-type fun_env() :: [{name(), fun_info()}].
|
||||||
-type type_env() :: [{name(), type_info()}].
|
-type type_env() :: [{name(), type_info()}].
|
||||||
@ -139,11 +139,11 @@ on_current_scope(Env = #env{ namespace = NS, scopes = Scopes }, Fun) ->
|
|||||||
on_scopes(Env = #env{ scopes = Scopes }, Fun) ->
|
on_scopes(Env = #env{ scopes = Scopes }, Fun) ->
|
||||||
Env#env{ scopes = maps:map(fun(_, Scope) -> Fun(Scope) end, Scopes) }.
|
Env#env{ scopes = maps:map(fun(_, Scope) -> Fun(Scope) end, Scopes) }.
|
||||||
|
|
||||||
-spec bind_var(aeso_syntax:id(), type(), env()) -> env().
|
-spec bind_var(aeso_syntax:id(), utype(), env()) -> env().
|
||||||
bind_var({id, Ann, X}, T, Env) ->
|
bind_var({id, Ann, X}, T, Env) ->
|
||||||
Env#env{ vars = [{X, {Ann, T}} | Env#env.vars] }.
|
Env#env{ vars = [{X, {Ann, T}} | Env#env.vars] }.
|
||||||
|
|
||||||
-spec bind_vars([{aeso_syntax:id(), type()}], env()) -> env().
|
-spec bind_vars([{aeso_syntax:id(), utype()}], env()) -> env().
|
||||||
bind_vars([], Env) -> Env;
|
bind_vars([], Env) -> Env;
|
||||||
bind_vars([{X, T} | Vars], Env) ->
|
bind_vars([{X, T} | Vars], Env) ->
|
||||||
bind_vars(Vars, bind_var(X, T, Env)).
|
bind_vars(Vars, bind_var(X, T, Env)).
|
||||||
@ -460,7 +460,8 @@ global_env() ->
|
|||||||
%% Crypto/Curve operations
|
%% Crypto/Curve operations
|
||||||
CryptoScope = #scope
|
CryptoScope = #scope
|
||||||
{ funs = MkDefs(
|
{ funs = MkDefs(
|
||||||
[{"ecverify", Fun([Hash, Address, SignId], Bool)},
|
[{"ecrecover_secp256k1", Fun([Hash, Bytes(65)], Hash)},
|
||||||
|
{"ecverify", Fun([Hash, Address, SignId], Bool)},
|
||||||
{"ecverify_secp256k1", Fun([Hash, Bytes(64), Bytes(64)], Bool)},
|
{"ecverify_secp256k1", Fun([Hash, Bytes(64), Bytes(64)], Bool)},
|
||||||
{"sha3", Fun1(A, Hash)},
|
{"sha3", Fun1(A, Hash)},
|
||||||
{"sha256", Fun1(A, Hash)},
|
{"sha256", Fun1(A, Hash)},
|
||||||
|
@ -33,7 +33,8 @@
|
|||||||
string_concat | bits_set | bits_clear | bits_test | bits_sum |
|
string_concat | bits_set | bits_clear | bits_test | bits_sum |
|
||||||
bits_intersection | bits_union | bits_difference |
|
bits_intersection | bits_union | bits_difference |
|
||||||
contract_to_address | crypto_ecverify | crypto_ecverify_secp256k1 |
|
contract_to_address | crypto_ecverify | crypto_ecverify_secp256k1 |
|
||||||
crypto_sha3 | crypto_sha256 | crypto_blake2b.
|
crypto_sha3 | crypto_sha256 | crypto_blake2b |
|
||||||
|
crypto_ecrecover_secp256k1.
|
||||||
|
|
||||||
-type flit() :: {int, integer()}
|
-type flit() :: {int, integer()}
|
||||||
| {string, binary()}
|
| {string, binary()}
|
||||||
@ -187,8 +188,8 @@ builtins() ->
|
|||||||
{"revoke", 3}]},
|
{"revoke", 3}]},
|
||||||
{["Map"], [{"from_list", 1}, {"to_list", 1}, {"lookup", 2},
|
{["Map"], [{"from_list", 1}, {"to_list", 1}, {"lookup", 2},
|
||||||
{"lookup_default", 3}, {"delete", 2}, {"member", 2}, {"size", 1}]},
|
{"lookup_default", 3}, {"delete", 2}, {"member", 2}, {"size", 1}]},
|
||||||
{["Crypto"], [{"ecverify", 3}, {"ecverify_secp256k1", 3}, {"sha3", 1},
|
{["Crypto"], [{"ecrecover_secp256k1", 2}, {"ecverify", 3}, {"ecverify_secp256k1", 3},
|
||||||
{"sha256", 1}, {"blake2b", 1}]},
|
{"sha3", 1}, {"sha256", 1}, {"blake2b", 1}]},
|
||||||
{["Auth"], [{"tx_hash", none}]},
|
{["Auth"], [{"tx_hash", none}]},
|
||||||
{["String"], [{"length", 1}, {"concat", 2}, {"sha3", 1}, {"sha256", 1}, {"blake2b", 1}]},
|
{["String"], [{"length", 1}, {"concat", 2}, {"sha3", 1}, {"sha256", 1}, {"blake2b", 1}]},
|
||||||
{["Bits"], [{"set", 2}, {"clear", 2}, {"test", 2}, {"sum", 1}, {"intersection", 2},
|
{["Bits"], [{"set", 2}, {"clear", 2}, {"test", 2}, {"sum", 1}, {"intersection", 2},
|
||||||
@ -818,7 +819,9 @@ op_builtins() ->
|
|||||||
string_length, string_concat, string_sha3, string_sha256, string_blake2b,
|
string_length, string_concat, string_sha3, string_sha256, string_blake2b,
|
||||||
bits_set, bits_clear, bits_test, bits_sum, bits_intersection, bits_union,
|
bits_set, bits_clear, bits_test, bits_sum, bits_intersection, bits_union,
|
||||||
bits_difference, int_to_str, address_to_str, crypto_ecverify,
|
bits_difference, int_to_str, address_to_str, crypto_ecverify,
|
||||||
crypto_ecverify_secp256k1, crypto_sha3, crypto_sha256, crypto_blake2b].
|
crypto_ecverify_secp256k1, crypto_sha3, crypto_sha256, crypto_blake2b,
|
||||||
|
crypto_ecrecover_secp256k1
|
||||||
|
].
|
||||||
|
|
||||||
builtin_to_fcode(require, [Cond, Msg]) ->
|
builtin_to_fcode(require, [Cond, Msg]) ->
|
||||||
make_if(Cond, {tuple, []}, {builtin, abort, [Msg]});
|
make_if(Cond, {tuple, []}, {builtin, abort, [Msg]});
|
||||||
|
@ -350,6 +350,11 @@ ast_body({map, Ann, Map, [Upd | Upds]}, Icode) ->
|
|||||||
ast_body({map, Ann, {map, Ann, Map, [Upd]}, Upds}, Icode);
|
ast_body({map, Ann, {map, Ann, Map, [Upd]}, Upds}, Icode);
|
||||||
|
|
||||||
%% Crypto
|
%% Crypto
|
||||||
|
ast_body(?qid_app(["Crypto", "ecrecover_secp256k1"], [Msg, Sig], _, _), Icode) ->
|
||||||
|
prim_call(?PRIM_CALL_CRYPTO_ECRECOVER_SECP256K1, #integer{value = 0},
|
||||||
|
[ast_body(Msg, Icode), ast_body(Sig, Icode)],
|
||||||
|
[word, bytes_t(65)], word);
|
||||||
|
|
||||||
ast_body(?qid_app(["Crypto", "ecverify"], [Msg, PK, Sig], _, _), Icode) ->
|
ast_body(?qid_app(["Crypto", "ecverify"], [Msg, PK, Sig], _, _), Icode) ->
|
||||||
prim_call(?PRIM_CALL_CRYPTO_ECVERIFY, #integer{value = 0},
|
prim_call(?PRIM_CALL_CRYPTO_ECVERIFY, #integer{value = 0},
|
||||||
[ast_body(Msg, Icode), ast_body(PK, Icode), ast_body(Sig, Icode)],
|
[ast_body(Msg, Icode), ast_body(PK, Icode), ast_body(Sig, Icode)],
|
||||||
|
@ -574,14 +574,13 @@ pp(Code, Options, Option, PPFun) ->
|
|||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
%% -------------------------------------------------------------------
|
%% -------------------------------------------------------------------
|
||||||
%% TODO: Tempoary parser hook below...
|
|
||||||
|
|
||||||
|
-spec parse_stdlib() -> none() | aeso_syntax:ast().
|
||||||
parse_stdlib() ->
|
parse_stdlib() ->
|
||||||
lists:foldr(
|
lists:foldr(
|
||||||
fun ({Lib, LibCode}, Acc) ->
|
fun ({Lib, LibCode}, Acc) ->
|
||||||
parse(LibCode, [{src_file, Lib}]) ++ Acc
|
parse(LibCode, [{src_file, binary_to_list(Lib)}]) ++ Acc
|
||||||
end,
|
end,
|
||||||
[],
|
[],
|
||||||
aeso_stdlib:stdlib_list()).
|
aeso_stdlib:stdlib_list()).
|
||||||
@ -593,8 +592,11 @@ sophia_type_to_typerep(String) ->
|
|||||||
catch _:_ -> {error, bad_type}
|
catch _:_ -> {error, bad_type}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec parse(string(), aeso_compiler:options()) -> none() | aeso_syntax:ast().
|
||||||
parse(Text, Options) ->
|
parse(Text, Options) ->
|
||||||
parse(Text, sets:new(), Options).
|
parse(Text, sets:new(), Options).
|
||||||
|
|
||||||
|
-spec parse(string(), sets:set(), aeso_compiler:options()) -> none() | aeso_syntax:ast().
|
||||||
parse(Text, Included, Options) ->
|
parse(Text, Included, Options) ->
|
||||||
%% Try and return something sensible here!
|
%% Try and return something sensible here!
|
||||||
case aeso_parser:string(Text, Included, Options) of
|
case aeso_parser:string(Text, Included, Options) of
|
||||||
@ -616,6 +618,7 @@ parse(Text, Included, Options) ->
|
|||||||
parse_error(Pos, io_lib:format("could not find include file '~s'", [File]))
|
parse_error(Pos, io_lib:format("could not find include file '~s'", [File]))
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec parse_error(aeso_parse_lib:pos(), string()) -> none().
|
||||||
parse_error(Pos, ErrorString) ->
|
parse_error(Pos, ErrorString) ->
|
||||||
Error = io_lib:format("~s: ~s", [pos_error(Pos), ErrorString]),
|
Error = io_lib:format("~s: ~s", [pos_error(Pos), ErrorString]),
|
||||||
error({parse_errors, [Error]}).
|
error({parse_errors, [Error]}).
|
||||||
|
@ -98,6 +98,7 @@
|
|||||||
Op =:= 'SHA3' orelse
|
Op =:= 'SHA3' orelse
|
||||||
Op =:= 'SHA256' orelse
|
Op =:= 'SHA256' orelse
|
||||||
Op =:= 'BLAKE2B' orelse
|
Op =:= 'BLAKE2B' orelse
|
||||||
|
Op =:= 'ECRECOVER_SECP256K1' orelse
|
||||||
Op =:= 'ECVERIFY' orelse
|
Op =:= 'ECVERIFY' orelse
|
||||||
Op =:= 'ECVERIFY_SECP256K1' orelse
|
Op =:= 'ECVERIFY_SECP256K1' orelse
|
||||||
Op =:= 'CONTRACT_TO_ADDRESS' orelse
|
Op =:= 'CONTRACT_TO_ADDRESS' orelse
|
||||||
@ -592,6 +593,7 @@ op_to_scode(bits_difference) -> aeb_fate_ops:bits_diff(?a, ?a, ?a);
|
|||||||
op_to_scode(address_to_str) -> aeb_fate_ops:addr_to_str(?a, ?a);
|
op_to_scode(address_to_str) -> aeb_fate_ops:addr_to_str(?a, ?a);
|
||||||
op_to_scode(int_to_str) -> aeb_fate_ops:int_to_str(?a, ?a);
|
op_to_scode(int_to_str) -> aeb_fate_ops:int_to_str(?a, ?a);
|
||||||
op_to_scode(contract_to_address) -> aeb_fate_ops:contract_to_address(?a, ?a);
|
op_to_scode(contract_to_address) -> aeb_fate_ops:contract_to_address(?a, ?a);
|
||||||
|
op_to_scode(crypto_ecrecover_secp256k1) -> aeb_fate_ops:ecrecover_secp256k1(?a, ?a, ?a);
|
||||||
op_to_scode(crypto_ecverify) -> aeb_fate_ops:ecverify(?a, ?a, ?a, ?a);
|
op_to_scode(crypto_ecverify) -> aeb_fate_ops:ecverify(?a, ?a, ?a, ?a);
|
||||||
op_to_scode(crypto_ecverify_secp256k1) -> aeb_fate_ops:ecverify_secp256k1(?a, ?a, ?a, ?a);
|
op_to_scode(crypto_ecverify_secp256k1) -> aeb_fate_ops:ecverify_secp256k1(?a, ?a, ?a, ?a);
|
||||||
op_to_scode(crypto_sha3) -> aeb_fate_ops:sha3(?a, ?a);
|
op_to_scode(crypto_sha3) -> aeb_fate_ops:sha3(?a, ?a);
|
||||||
@ -819,6 +821,7 @@ attributes(I) ->
|
|||||||
{'SHA3', A, B} -> Pure(A, [B]);
|
{'SHA3', A, B} -> Pure(A, [B]);
|
||||||
{'SHA256', A, B} -> Pure(A, [B]);
|
{'SHA256', A, B} -> Pure(A, [B]);
|
||||||
{'BLAKE2B', A, B} -> Pure(A, [B]);
|
{'BLAKE2B', A, B} -> Pure(A, [B]);
|
||||||
|
{'ECRECOVER_SECP256K1', A, B, C} -> Pure(A, [B, C]);
|
||||||
{'ECVERIFY', A, B, C, D} -> Pure(A, [B, C, D]);
|
{'ECVERIFY', A, B, C, D} -> Pure(A, [B, C, D]);
|
||||||
{'ECVERIFY_SECP256K1', A, B, C, D} -> Pure(A, [B, C, D]);
|
{'ECVERIFY_SECP256K1', A, B, C, D} -> Pure(A, [B, C, D]);
|
||||||
{'CONTRACT_TO_ADDRESS', A, B} -> Pure(A, [B]);
|
{'CONTRACT_TO_ADDRESS', A, B} -> Pure(A, [B]);
|
||||||
|
@ -22,8 +22,7 @@
|
|||||||
string(String) ->
|
string(String) ->
|
||||||
string(String, sets:new(), []).
|
string(String, sets:new(), []).
|
||||||
|
|
||||||
|
-spec string(string(), aeso_compiler:options()) -> parse_result().
|
||||||
-spec string(string(), compiler:options()) -> parse_result().
|
|
||||||
string(String, Opts) ->
|
string(String, Opts) ->
|
||||||
case lists:keyfind(src_file, 1, Opts) of
|
case lists:keyfind(src_file, 1, Opts) of
|
||||||
{src_file, File} -> string(String, sets:add_element(File, sets:new()), Opts);
|
{src_file, File} -> string(String, sets:add_element(File, sets:new()), Opts);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user