Switched to C based nif
This commit is contained in:
parent
39ab0b2caa
commit
53b4d36a29
@ -1,5 +0,0 @@
|
|||||||
[target.'cfg(target_os = "macos")']
|
|
||||||
rustflags = [
|
|
||||||
"-C", "link-arg=-undefined",
|
|
||||||
"-C", "link-arg=dynamic_lookup",
|
|
||||||
]
|
|
@ -23,8 +23,6 @@ commands:
|
|||||||
&& sudo apt-get \
|
&& sudo apt-get \
|
||||||
install \
|
install \
|
||||||
build-essential \
|
build-essential \
|
||||||
cargo \
|
|
||||||
cmake \
|
|
||||||
autoconf \
|
autoconf \
|
||||||
libncurses5-dev
|
libncurses5-dev
|
||||||
- run:
|
- run:
|
||||||
@ -33,10 +31,6 @@ commands:
|
|||||||
curl -fsSL -o otp-src.tar.gz https://github.com/erlang/otp/archive/OTP-<< parameters.OTP_VERSION >>.tar.gz
|
curl -fsSL -o otp-src.tar.gz https://github.com/erlang/otp/archive/OTP-<< parameters.OTP_VERSION >>.tar.gz
|
||||||
tar -zxf otp-src.tar.gz --strip-components=1
|
tar -zxf otp-src.tar.gz --strip-components=1
|
||||||
./otp_build autoconf && ./configure && make -j$(nproc) && sudo make install
|
./otp_build autoconf && ./configure && make -j$(nproc) && sudo make install
|
||||||
- run:
|
|
||||||
name: Install rest
|
|
||||||
command: |
|
|
||||||
curl https://sh.rustup.rs -sSf | sh -s -- -yq && source $HOME/.cargo/env
|
|
||||||
|
|
||||||
setup_macos:
|
setup_macos:
|
||||||
description: "Setup macos environment"
|
description: "Setup macos environment"
|
||||||
@ -49,7 +43,7 @@ commands:
|
|||||||
name: Setup environment
|
name: Setup environment
|
||||||
command: |
|
command: |
|
||||||
brew update
|
brew update
|
||||||
brew install rust cmake erlang@<< parameters.OTP_VERSION >>
|
brew install erlang@<< parameters.OTP_VERSION >>
|
||||||
brew link --force erlang@<< parameters.OTP_VERSION >>
|
brew link --force erlang@<< parameters.OTP_VERSION >>
|
||||||
|
|
||||||
run_build:
|
run_build:
|
||||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,8 +1,7 @@
|
|||||||
/target
|
|
||||||
**/*.rs.bk
|
|
||||||
**/*~
|
**/*~
|
||||||
/parity-ethereum
|
|
||||||
/_build
|
/_build
|
||||||
/ebin
|
/ebin
|
||||||
/priv/ecrecover.dll
|
/priv/ecrecover.dll
|
||||||
/priv/ecrecover.so
|
/priv/ecrecover.so
|
||||||
|
/c_src/ecrecover.d
|
||||||
|
/c_src/ecrecover.o
|
||||||
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "c_src/secp256k1"]
|
||||||
|
path = c_src/secp256k1
|
||||||
|
url = https://github.com/bitcoin-core/secp256k1.git
|
1996
Cargo.lock
generated
1996
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
19
Cargo.toml
19
Cargo.toml
@ -1,19 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "ecrecover"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["John Newby <john@newby.org>"]
|
|
||||||
edition = "2018"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
base64 = "0.10.1"
|
|
||||||
c_vec = "1.3.3"
|
|
||||||
ethcore-builtin = { git = "https://github.com/paritytech/parity-ethereum.git", rev = "acf7c48" }
|
|
||||||
lazy_static = "1.3.0"
|
|
||||||
libc = "0.2.60"
|
|
||||||
parity-bytes = "0.1.0"
|
|
||||||
rustler = "0.21.0"
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
crate-type = ["cdylib"]
|
|
30
Makefile
30
Makefile
@ -1,30 +0,0 @@
|
|||||||
UNAME := $(shell uname)
|
|
||||||
|
|
||||||
ifeq ($(OS),Windows_NT)
|
|
||||||
nif_lib_src = ecrecover.dll
|
|
||||||
nif_lib = ecrecover.dll
|
|
||||||
else
|
|
||||||
ifeq ($(UNAME), Linux)
|
|
||||||
nif_lib_src = libecrecover.so
|
|
||||||
nif_lib = ecrecover.so
|
|
||||||
endif
|
|
||||||
ifeq ($(UNAME), Darwin)
|
|
||||||
nif_lib_src = libecrecover.dylib
|
|
||||||
nif_lib = ecrecover.so
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
all: priv/$(nif_lib) compile
|
|
||||||
|
|
||||||
compile:
|
|
||||||
./rebar3 compile
|
|
||||||
|
|
||||||
priv/$(nif_lib): src/lib.rs
|
|
||||||
ifneq ($(ECRECOVER_DISABLE_NIF_BUILD), true)
|
|
||||||
cargo build --release
|
|
||||||
cp target/release/$(nif_lib_src) $@
|
|
||||||
endif
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f priv/$(nif_lib) target/release/$(nif_lib_src)
|
|
||||||
./rebar3 clean
|
|
25
Makefile.win32
Normal file
25
Makefile.win32
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
secp256k1_dir := c_src/secp256k1
|
||||||
|
secp256k1_lib_dir := c_src/secp256k1/.libs
|
||||||
|
|
||||||
|
CFLAGS := -MT -DNOMINMAX -Ox -DNDEBUG -openmp -W4 -Zi -EHsc -nologo -I$(secp256k1_dir)/include
|
||||||
|
LDFLAGS := -LIBPATH:$(secp256k1_lib_dir) -nologo
|
||||||
|
|
||||||
|
.PHONY: win32_ecrecover
|
||||||
|
win32_ecrecover: $(secp256k1_lib_dir)/libsecp256k1.lib
|
||||||
|
|
||||||
|
$(secp256k1_lib_dir)/libsecp256k1.lib: $(secp256k1_lib_dir)/secp256k1.lib
|
||||||
|
lib ${LDFLAGS} -OUT:$@ -nodefaultlib $^
|
||||||
|
|
||||||
|
$(secp256k1_lib_dir)/secp256k1.lib: $(secp256k1_obj_dir)/fp.obj
|
||||||
|
lib ${LDFLAGS} -OUT:$@ -nodefaultlib $<
|
||||||
|
|
||||||
|
$(secp256k1_obj_dir)/fp.obj: $(secp256k1_src_dir)/fp.cpp
|
||||||
|
cl -c ${CFLAGS} $< -Fo$@
|
||||||
|
|
||||||
|
$(secp256k1_obj_dir)/bn_c384_256.obj: $(secp256k1_src_dir)/bn_c384_256.cpp
|
||||||
|
cl -c ${CFLAGS} $< -Fo$@
|
||||||
|
|
||||||
|
clean_win32_secp256k1:
|
||||||
|
make -C $(secp256k1_dir) clean
|
||||||
|
rm -f $(secp256k1_lib_dir)/*.lib $(secp256k1_lib_dir)/*.dll $(secp256k1_lib_dir)/*.exp
|
||||||
|
|
102
c_src/ecrecover.c
Normal file
102
c_src/ecrecover.c
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
#include "erl_nif.h"
|
||||||
|
#include "secp256k1_recovery.h"
|
||||||
|
|
||||||
|
|
||||||
|
static secp256k1_context *ctx = NULL;
|
||||||
|
|
||||||
|
static ERL_NIF_TERM error_result(ErlNifEnv* env, char* error_msg)
|
||||||
|
{
|
||||||
|
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_string(env, error_msg, ERL_NIF_LATIN1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static ERL_NIF_TERM ok_result(ErlNifEnv* env, ERL_NIF_TERM *r)
|
||||||
|
{
|
||||||
|
return enif_make_tuple2(env, enif_make_atom(env, "ok"), *r);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ERL_NIF_TERM
|
||||||
|
recover(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
|
||||||
|
{
|
||||||
|
ERL_NIF_TERM r;
|
||||||
|
ErlNifBinary message, csignature;
|
||||||
|
int result;
|
||||||
|
int compressed = SECP256K1_EC_UNCOMPRESSED;
|
||||||
|
size_t pubkeylen = 65;
|
||||||
|
int recid;
|
||||||
|
unsigned char* finished_recpubkey_buf;
|
||||||
|
secp256k1_ecdsa_recoverable_signature signature;
|
||||||
|
secp256k1_pubkey recpubkey;
|
||||||
|
|
||||||
|
if (!enif_inspect_binary(env, argv[0], &message)) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_inspect_binary(env, argv[1], &csignature)) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_get_int(env, argv[2], &recid)) {
|
||||||
|
return error_result(env, "Recovery id invalid 0-3");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recid < 0 || recid > 3) {
|
||||||
|
error_result(env, "Recovery id invalid 0-3x");
|
||||||
|
}
|
||||||
|
printf("xx1\r\n");
|
||||||
|
result = secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &signature, csignature.data, recid);
|
||||||
|
printf("xx2\r\n");
|
||||||
|
if (!result) {
|
||||||
|
return error_result(env, "ecdsa_signature_parse_compact returned 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now do ECDSA recovery
|
||||||
|
result = secp256k1_ecdsa_recover(ctx, &recpubkey, &signature, message.data);
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return error_result(env, "ecdsa recovery problem");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now serialize recpubkey based on the compression flag
|
||||||
|
finished_recpubkey_buf = enif_make_new_binary(env, pubkeylen, &r);
|
||||||
|
|
||||||
|
printf("pubker[0] = %d\r\n", recpubkey.data[0]);
|
||||||
|
|
||||||
|
|
||||||
|
result = secp256k1_ec_pubkey_serialize(ctx, finished_recpubkey_buf,
|
||||||
|
&pubkeylen, &recpubkey, compressed);
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return error_result(env, "ecdsa pubkey serialize error");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok_result(env, &r);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
load(ErlNifEnv* env, void** priv, ERL_NIF_TERM load_info)
|
||||||
|
{
|
||||||
|
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
upgrade(ErlNifEnv* env, void** priv, void** old_priv, ERL_NIF_TERM load_info)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
unload(ErlNifEnv* env, void* priv)
|
||||||
|
{
|
||||||
|
secp256k1_context_destroy(ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ErlNifFunc nif_funcs[] =
|
||||||
|
{
|
||||||
|
{"recover", 3, recover}
|
||||||
|
};
|
||||||
|
|
||||||
|
ERL_NIF_INIT(ecrecover, nif_funcs, &load, NULL, NULL, &unload);
|
1
c_src/secp256k1
Submodule
1
c_src/secp256k1
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit cbe41ac138bc0773d60ab1942b7ad6fc5eccfc19
|
@ -1 +0,0 @@
|
|||||||
4717328000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18000000000000000000000000f941ba12e03
|
|
@ -1 +0,0 @@
|
|||||||
47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03
|
|
@ -1,7 +0,0 @@
|
|||||||
#if !defined __AE__BASE64_H
|
|
||||||
#define __AE__BASE64_H
|
|
||||||
|
|
||||||
char *bin2hex(unsigned char*, int);
|
|
||||||
unsigned char *hex2bin(const char*);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,6 +0,0 @@
|
|||||||
#if !defined __AE_ECRECOVER_H
|
|
||||||
#define __AE_ECRECOVER_H
|
|
||||||
|
|
||||||
int ecrecover(const unsigned char *input, unsigned char *output);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,10 +0,0 @@
|
|||||||
#include <cstdarg>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <new>
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
void ecrecover(const unsigned char *input, unsigned char *output);
|
|
||||||
|
|
||||||
} // extern "C"
|
|
@ -1,20 +0,0 @@
|
|||||||
#if !defined __AE__ERL_COMM_H
|
|
||||||
#define __AE__ERL_COMM_H
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
#include <stdio.h>
|
|
||||||
#define DEBUG_PRINTF printf
|
|
||||||
#else
|
|
||||||
#define DEBUG_PRINTF
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef unsigned char byte;
|
|
||||||
|
|
||||||
#define ECRECOVER_BUFFER_MAX 1024
|
|
||||||
|
|
||||||
int read_cmd(byte *buf);
|
|
||||||
int write_cmd(byte *buf, int len);
|
|
||||||
int read_exact(byte *buf, int len);
|
|
||||||
int write_exact(byte *buf, int len);
|
|
||||||
|
|
||||||
#endif
|
|
46
rebar.config
46
rebar.config
@ -1,17 +1,39 @@
|
|||||||
{deps, [
|
{deps,
|
||||||
%% ecrecover prebuilt libraries
|
[{sha3, {git, "https://github.com/aeternity/erlang-sha3", {ref, "b5f27a2"}}}]}.
|
||||||
{ecrecoverprebuilt,
|
|
||||||
{ecrecoverprebuilt_app_with_priv_from_git,
|
|
||||||
{git, "https://github.com/aeternity/ecrecover-prebuilt.git",
|
|
||||||
{ref, "4027374"}}}}
|
|
||||||
]}.
|
|
||||||
|
|
||||||
{plugins, [{rebar_ecrecoverprebuilt_dep,
|
{pre_hooks, [ {compile, "git submodule update --init"}
|
||||||
{git, "https://github.com/aeternity/rebar3-ecrecover-prebuilt-plugin.git",
|
, {"(linux|darwin)", compile, "sh -c \"cd c_src/secp256k1 && ./autogen.sh && ./configure --enable-module-recovery && make\""}
|
||||||
{ref, "7286efd"}}}
|
, {"win32", compile, "make -f Makefile.win32 win32_ecrecover"}
|
||||||
]}.
|
]}.
|
||||||
|
|
||||||
|
{post_hooks, [ {"(linux|darwin)", clean, "make -C \"c_src/secp256k1\" clean"}
|
||||||
|
, {"win32", clean, "make -f Makefile.win32 clean_win32_ecrecover"}
|
||||||
|
]}.
|
||||||
|
|
||||||
|
|
||||||
|
{plugins, [pc]}.
|
||||||
|
|
||||||
|
{provider_hooks, [
|
||||||
|
{post, [ {compile, {pc, compile}}
|
||||||
|
, {clean, {pc, clean}}
|
||||||
|
]}
|
||||||
|
]}.
|
||||||
|
|
||||||
|
{port_specs, [{"priv/ecrecover.so", ["c_src/*.c"]}]}.
|
||||||
|
|
||||||
|
{port_env, [ {"darwin", "CFLAGS", "$CFLAGS -fPIC -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes -I c_src/secp256k1/include"}
|
||||||
|
, {"darwin", "CXXFLAGS", "$CXXFLAGS -fPIC -O3 -finline-functions -Wall"}
|
||||||
|
, {"darwin", "LDFLAGS", "$LDFLAGS c_src/secp256k1/.libs/libsecp256k1.a"}
|
||||||
|
|
||||||
|
, {"linux", "CFLAGS", "$CFLAGS -fPIC -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes -I c_src/secp256k1/include"}
|
||||||
|
, {"linux", "CXXFLAGS", "$CXXFLAGS -fPIC -O3 -finline-functions -Wall"}
|
||||||
|
, {"linux", "LDFLAGS", "$LDFLAGS c_src/secp256k1/.libs/libsecp256k1.a -lstdc++"}
|
||||||
|
|
||||||
|
, {"win32", "CFLAGS", "$CFLAGS /LD /MD /Fe /Ox /DNDEBUG /DMCLBN_DONT_EXPORT /Ic_src/secp256k1/include"}
|
||||||
|
, {"win32", "LDFLAGS", "$LDFLAGS /LIBPATH:c_src/cybozulib_ext/lib c_src/secp256k1/.libs/secp256k1.lib"}
|
||||||
|
]}.
|
||||||
|
|
||||||
{dialyzer, [{warnings, [unknown]},
|
{dialyzer, [{warnings, [unknown]},
|
||||||
{plt_apps, all_deps},
|
{plt_apps, all_deps},
|
||||||
{base_plt_apps, [erts, kernel, stdlib, crypto]}
|
{base_plt_apps, [erts, kernel, stdlib]}
|
||||||
]}.
|
]}.
|
||||||
|
@ -1,5 +1 @@
|
|||||||
[{<<"ecrecoverprebuilt">>,
|
[].
|
||||||
{ecrecoverprebuilt_app_with_priv_from_git,
|
|
||||||
{git,"https://github.com/aeternity/ecrecover-prebuilt.git",
|
|
||||||
{ref,"402737411420fc4c500e1f42c921ef185a35cc56"}}},
|
|
||||||
0}].
|
|
||||||
|
@ -4,8 +4,7 @@
|
|||||||
{registered, []},
|
{registered, []},
|
||||||
{applications,
|
{applications,
|
||||||
[kernel,
|
[kernel,
|
||||||
stdlib,
|
stdlib
|
||||||
ecrecoverprebuilt
|
|
||||||
]},
|
]},
|
||||||
{env,[]},
|
{env,[]},
|
||||||
{modules, []},
|
{modules, []},
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
-module(ecrecover).
|
-module(ecrecover).
|
||||||
|
|
||||||
|
%% https://github.com/mbrix/libsecp256k1
|
||||||
|
|
||||||
%% API
|
%% API
|
||||||
-export([recover/2]).
|
-export([recover/2, recover/3]).
|
||||||
|
|
||||||
%% NIF
|
%% NIF
|
||||||
-export([load/0]).
|
-export([load/0]).
|
||||||
@ -9,16 +11,17 @@
|
|||||||
|
|
||||||
%%=============================================================================
|
%%=============================================================================
|
||||||
%% NIF API
|
%% NIF API
|
||||||
|
%% GoodMsg1 = <<71,23,50,133,168,215,52,30,94,151,47,198,119,40,99,132,248,2,248,239,66,165,236,95,3,187,250,37,76,176,31,173>>.
|
||||||
|
%% GoodSig1_v = <<27,101,10,207,157,63,95,10,44,121,151,118,161,37,67,85,213,244,6,23,98,162,55,57,106,153,160,224,227,252,43,205,103,41,81,74,13,172,178,230,35,172,74,189,21,124,177,129,99,255,148,34,128,219,77,92,170,214,109,223,148,27,161,46,3>>.
|
||||||
|
%% ecrecover:recover(<<71,23,50,133,168,215,52,30,94,151,47,198,119,40,99,132,248,2,248,239,66,165,236,95,3,187,250,37,76,176,31,173>>, <<27,101,10,207,157,63,95,10,44,121,151,118,161,37,67,85,213,244,6,23,98,162,55,57,106,153,160,224,227,252,43,205,103,41,81,74,13,172,178,230,35,172,74,189,21,124,177,129,99,255,148,34,128,219,77,92,170,214,109,223,148,27,161,46,3>>).
|
||||||
|
%%
|
||||||
|
|
||||||
load() ->
|
load() ->
|
||||||
% Prefer locally built NIF (good for testing and exotic platforms) over
|
EbinDir = filename:dirname(code:which(?MODULE)),
|
||||||
% prebuilt binaries.
|
AppDir = filename:dirname(EbinDir),
|
||||||
case load_local_nif() of
|
PrivDir = filename:join(AppDir, "priv"),
|
||||||
ok ->
|
SoName = filename:join(PrivDir, atom_to_list(?MODULE)),
|
||||||
ok;
|
erlang:load_nif(SoName, 0).
|
||||||
{error, _} ->
|
|
||||||
load_prebuilt_nif()
|
|
||||||
end.
|
|
||||||
|
|
||||||
not_loaded(Line) ->
|
not_loaded(Line) ->
|
||||||
erlang:nif_error({error, {not_loaded, [{module, ?MODULE}, {line, Line}]}}).
|
erlang:nif_error({error, {not_loaded, [{module, ?MODULE}, {line, Line}]}}).
|
||||||
@ -26,36 +29,22 @@ not_loaded(Line) ->
|
|||||||
%%=============================================================================
|
%%=============================================================================
|
||||||
%% External API
|
%% External API
|
||||||
|
|
||||||
-spec recover(<<_:(32*8)>>, <<_:(65*8)>>) -> <<_:(32*8)>>.
|
recover(Hash, <<V, Sig:64/binary>>) when V == 27; V == 28 ->
|
||||||
recover(<<_:32/binary>> = Hash, <<_:65/binary>> = Sig) ->
|
RecId = V - 27,
|
||||||
Input = <<Hash/binary, 0:(8*31), Sig/binary>>,
|
case recover(Hash, Sig, RecId) of
|
||||||
case recover_(Input) of
|
{ok, <<4, XY:64/binary>>} ->
|
||||||
{ok, []} ->
|
<<_:12/bytes, ShortPub:20/bytes>> = keccak256(XY),
|
||||||
<<0:256>>;
|
<<0:96, ShortPub/binary>>;
|
||||||
{ok, Res} ->
|
{error, _} ->
|
||||||
erlang:list_to_binary(Res);
|
|
||||||
_Err ->
|
|
||||||
<<0:256>>
|
<<0:256>>
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec recover(<<_:(32*8)>>, <<_:(65*8)>>, integer()) -> <<_:(32*8)>>.
|
||||||
|
recover(_Hash, _Sig, _RecId) ->
|
||||||
|
not_loaded(?LINE).
|
||||||
|
|
||||||
%%=============================================================================
|
%%=============================================================================
|
||||||
%% Internal Functions
|
%% Internal Functions
|
||||||
|
|
||||||
load_local_nif() ->
|
keccak256(Bin) ->
|
||||||
EbinDir = filename:dirname(code:which(?MODULE)),
|
sha3:hash(256, Bin).
|
||||||
AppDir = filename:dirname(EbinDir),
|
|
||||||
PrivDir = filename:join(AppDir, "priv"),
|
|
||||||
SoName = filename:join(PrivDir, atom_to_list(?MODULE)),
|
|
||||||
erlang:load_nif(SoName, 0).
|
|
||||||
|
|
||||||
load_prebuilt_nif() ->
|
|
||||||
case code:priv_dir(ecrecoverprebuilt) of
|
|
||||||
{error, _} ->
|
|
||||||
{error, prebuilt_priv_dir_not_found};
|
|
||||||
PrivDir ->
|
|
||||||
SoName = filename:join(PrivDir, atom_to_list(?MODULE)),
|
|
||||||
erlang:load_nif(SoName, 0)
|
|
||||||
end.
|
|
||||||
|
|
||||||
recover_(_Input) ->
|
|
||||||
not_loaded(?LINE).
|
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
-module(ecrecover_util).
|
|
||||||
|
|
||||||
-export([ recover_from_hex/1
|
|
||||||
, bin_to_hex/1
|
|
||||||
, hex_to_bin/1
|
|
||||||
]).
|
|
||||||
|
|
||||||
%%=============================================================================
|
|
||||||
%% External API
|
|
||||||
|
|
||||||
recover_from_hex(Input) ->
|
|
||||||
<<Hash:32/binary, _:31/binary, Sig:65/binary>> = hex_to_bin(Input),
|
|
||||||
PubKey = ecrecover:recover(Hash, Sig),
|
|
||||||
bin_to_hex(PubKey).
|
|
||||||
|
|
||||||
bin_to_hex(Bin) ->
|
|
||||||
lists:flatten([io_lib:format("~2.16.0B", [X]) || X <- binary_to_list(Bin)]).
|
|
||||||
|
|
||||||
hex_to_bin(S) ->
|
|
||||||
hex_to_bin(S, []).
|
|
||||||
hex_to_bin([], Acc) ->
|
|
||||||
list_to_binary(lists:reverse(Acc));
|
|
||||||
hex_to_bin([X,Y|T], Acc) ->
|
|
||||||
{ok, [V], []} = io_lib:fread("~16u", [X,Y]),
|
|
||||||
hex_to_bin(T, [V | Acc]);
|
|
||||||
hex_to_bin([X|T], Acc) ->
|
|
||||||
{ok, [V], []} = io_lib:fread("~16u", lists:flatten([X,"0"])),
|
|
||||||
hex_to_bin(T, [V | Acc]).
|
|
42
src/lib.rs
42
src/lib.rs
@ -1,42 +0,0 @@
|
|||||||
extern crate c_vec;
|
|
||||||
extern crate ethcore_builtin;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate lazy_static;
|
|
||||||
extern crate libc;
|
|
||||||
extern crate parity_bytes;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate rustler;
|
|
||||||
|
|
||||||
use crate::ethcore_builtin::Implementation;
|
|
||||||
use ethcore_builtin::EcRecover;
|
|
||||||
use parity_bytes::BytesRef;
|
|
||||||
use rustler::*;
|
|
||||||
|
|
||||||
mod atoms {
|
|
||||||
rustler_atoms! {
|
|
||||||
atom ok;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rustler_export_nifs!(
|
|
||||||
"ecrecover",
|
|
||||||
[("recover_", 1, nif_ecrecover),],
|
|
||||||
Some(on_load)
|
|
||||||
);
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
fn on_load(_env: Env, _load_info: Term) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn nif_ecrecover<'a>(env: Env<'a>, args: &[Term<'a>]) -> Result<Term<'a>, Error> {
|
|
||||||
let input: Binary = args[0].decode()?;
|
|
||||||
let mut byte_ref = Vec::new();
|
|
||||||
let ecrecover = EcRecover {};
|
|
||||||
let _result = match ecrecover.execute(input.as_slice(), &mut BytesRef::Flexible(&mut byte_ref))
|
|
||||||
{
|
|
||||||
Ok(_) => (),
|
|
||||||
Err(_e) => return Err(rustler::Error::Atom("ecrecover_failed")),
|
|
||||||
};
|
|
||||||
Ok((atoms::ok(), byte_ref.as_slice()).encode(env))
|
|
||||||
}
|
|
22
test/ecrecover_tests.erl
Normal file
22
test/ecrecover_tests.erl
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
%%%=============================================================================
|
||||||
|
%%% @copyright (C) 2023, Aeternity Foundation
|
||||||
|
%%% @doc
|
||||||
|
%%% Unit tests for ecrecover
|
||||||
|
%%% @end
|
||||||
|
%%%=============================================================================
|
||||||
|
-module(ecrecover_tests).
|
||||||
|
|
||||||
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
|
%% MSG and SIG from aecontract_SUITE, in turn taken from
|
||||||
|
%% https://github.com/aeternity/parity-ethereum/blob/master/ethcore/builtin/src/lib.rs#L656
|
||||||
|
%% GoodHexSig1 = "47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03",
|
||||||
|
%% <<GoodMsg1:32/binary, _:31/binary, GoodSig1_v:65/binary>> = aeu_hex:hex_to_bin(GoodHexSig1)
|
||||||
|
-define(MSG, <<71,23,50,133,168,215,52,30,94,151,47,198,119,40,99,132,248,2,248,239,66,165,236,95,3,187,250,37,76,176,31,173>>).
|
||||||
|
-define(SIG, <<27,101,10,207,157,63,95,10,44,121,151,118,161,37,67,85,213,244,6,23,98,162,55,57,106,153,160,224,227,252,43,205,103,41,81,74,13,172,178,230,35,172,74,189,21,124,177,129,99,255,148,34,128,219,77,92,170,214,109,223,148,27,161,46,3>>).
|
||||||
|
-define(EXPECTED_PUBKEY, <<0,0,0,0,0,0,0,0,0,0,0,0,192,139,85,66,209,119,172,102,134,148,105,32,64,151,65,70,58,21,221,219>>).
|
||||||
|
|
||||||
|
|
||||||
|
recover_test() ->
|
||||||
|
PubKey = ecrecover:recover(?MSG, ?SIG),
|
||||||
|
?assertEqual(?EXPECTED_PUBKEY, PubKey).
|
Loading…
x
Reference in New Issue
Block a user