Merge pull request #17 from aeternity/sh-switch-to-c-nif
Switch to c nif
This commit is contained in:
commit
ea35734a06
@ -1,5 +0,0 @@
|
||||
[target.'cfg(target_os = "macos")']
|
||||
rustflags = [
|
||||
"-C", "link-arg=-undefined",
|
||||
"-C", "link-arg=dynamic_lookup",
|
||||
]
|
@ -7,7 +7,9 @@ executors:
|
||||
macos_1106:
|
||||
macos:
|
||||
xcode: "13.2.1"
|
||||
|
||||
nix_alpine_ci:
|
||||
docker:
|
||||
- image: nixorg/nix:circleci
|
||||
commands:
|
||||
setup_ubuntu:
|
||||
description: "Setup Ubuntu environment"
|
||||
@ -22,20 +24,18 @@ commands:
|
||||
&& sudo apt-get \
|
||||
install \
|
||||
build-essential \
|
||||
cargo \
|
||||
cmake \
|
||||
autoconf \
|
||||
libncurses5-dev
|
||||
- run:
|
||||
name: Install OTP
|
||||
command: |
|
||||
mkdir otp_src
|
||||
cd otp_src
|
||||
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
|
||||
./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
|
||||
cd ..
|
||||
rm -fr otp_src
|
||||
|
||||
setup_macos:
|
||||
description: "Setup macos environment"
|
||||
@ -47,67 +47,40 @@ commands:
|
||||
name: Setup environment
|
||||
command: |
|
||||
brew update
|
||||
brew install rust cmake erlang@<< parameters.OTP_VERSION >>
|
||||
brew install erlang@<< parameters.OTP_VERSION >>
|
||||
brew link --force erlang@<< parameters.OTP_VERSION >>
|
||||
|
||||
run_build:
|
||||
description: "Build"
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Build
|
||||
command: |
|
||||
make
|
||||
|
||||
command: make
|
||||
- run:
|
||||
name: Test
|
||||
command: make test
|
||||
jobs:
|
||||
ubuntu_2004_otp21:
|
||||
executor: ubuntu_2004
|
||||
steps:
|
||||
- checkout
|
||||
- setup_ubuntu:
|
||||
OTP_VERSION: "21.3.8.24"
|
||||
- run_build
|
||||
ubuntu_2004_otp22:
|
||||
executor: ubuntu_2004
|
||||
steps:
|
||||
- checkout
|
||||
- setup_ubuntu:
|
||||
OTP_VERSION: "22.3.4.26"
|
||||
- run_build
|
||||
ubuntu_2004_otp23:
|
||||
executor: ubuntu_2004
|
||||
steps:
|
||||
- checkout
|
||||
- setup_ubuntu:
|
||||
OTP_VERSION: "23.3.4.18"
|
||||
- run_build
|
||||
macos_1106_otp21:
|
||||
executor: macos_1106
|
||||
steps:
|
||||
- checkout
|
||||
- setup_macos:
|
||||
OTP_VERSION: "21"
|
||||
- run_build
|
||||
macos_1106_otp22:
|
||||
executor: macos_1106
|
||||
steps:
|
||||
- checkout
|
||||
- setup_macos:
|
||||
OTP_VERSION: "22"
|
||||
- run_build
|
||||
macos_1106_otp23:
|
||||
executor: macos_1106
|
||||
steps:
|
||||
- checkout
|
||||
- setup_macos:
|
||||
OTP_VERSION: "23"
|
||||
- run_build
|
||||
|
||||
nix_alpine:
|
||||
executor: nix_alpine_ci
|
||||
steps:
|
||||
- checkout
|
||||
- run: nix-shell -j auto --run "./rebar3 do get-deps, compile, eunit -v"
|
||||
workflows:
|
||||
check:
|
||||
jobs:
|
||||
- ubuntu_2004_otp21
|
||||
- ubuntu_2004_otp22
|
||||
- ubuntu_2004_otp23
|
||||
- macos_1106_otp21
|
||||
- macos_1106_otp22
|
||||
- macos_1106_otp23
|
||||
- nix_alpine
|
||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,8 +1,8 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
**/*~
|
||||
/parity-ethereum
|
||||
/_build
|
||||
/ebin
|
||||
/priv/ecrecover.dll
|
||||
/priv/ecrecover.so
|
||||
/c_src/ecrecover.d
|
||||
/c_src/ecrecover.o
|
||||
/c_src/secp256k1
|
||||
|
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"]
|
33
Makefile
33
Makefile
@ -1,30 +1,13 @@
|
||||
UNAME := $(shell uname)
|
||||
REBAR3 ?= $(shell test -e `which rebar3` 2>/dev/null && which rebar3 || echo "./rebar3")
|
||||
|
||||
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
|
||||
all: 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
|
||||
${REBAR3} compile
|
||||
|
||||
clean:
|
||||
rm -f priv/$(nif_lib) target/release/$(nif_lib_src)
|
||||
./rebar3 clean
|
||||
${REBAR3} clean
|
||||
@rm -fr c_src/secp256k1
|
||||
|
||||
test: compile
|
||||
${REBAR3} eunit
|
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
|
||||
|
41
README.md
41
README.md
@ -1,40 +1,31 @@
|
||||
# ecrecover
|
||||
FFI (NIF) export of Ethereum's ecrecover for use from Erlang.
|
||||
FFI (NIF) export of Ethereum's ecrecover for use from Erlang based on
|
||||
https://github.com/bitcoin-core/secp256k1.git
|
||||
|
||||
### Prerequisites
|
||||
The NIF is written in Rust, therefore the following additional build
|
||||
dependencies are needed:
|
||||
|
||||
- Rust
|
||||
- Cargo
|
||||
- Cmake
|
||||
|
||||
### Build
|
||||
Execute:
|
||||
```
|
||||
make
|
||||
./rebar3 compile
|
||||
```
|
||||
|
||||
To disable the local build of the NIF library, e.g. to use a prebuilt binary,
|
||||
use the following command:
|
||||
```
|
||||
ECRECOVER_DISABLE_NIF_BUILD=true make
|
||||
```
|
||||
|
||||
## Erlang integration
|
||||
|
||||
The shared library uses NIF. Use the Erlang file `src/ecrecover.erl` to use this:
|
||||
|
||||
```
|
||||
c("src/ecrecover").
|
||||
c("src/ecrecover_util").
|
||||
Decoded = ecrecover_util:hex_to_bin("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").
|
||||
List = binary:bin_to_list(Decoded).
|
||||
Hash = binary:list_to_bin(lists:sublist(List, 1, 32)).
|
||||
Sig = binary:list_to_bin(lists:sublist(List, 64, 65)).
|
||||
Input = <<Hash/binary, 0:(8*31), Sig/binary>>.
|
||||
binary:bin_to_list(Input) == binary:bin_to_list(Decoded).
|
||||
Result = ecrecover:recover(Hash, Sig).
|
||||
Expected = ecrecover_util:hex_to_bin("000000000000000000000000c08b5542d177ac6686946920409741463a15dddb").
|
||||
binary:bin_to_list(Result) == binary:bin_to_list(Expected). %% check result
|
||||
./rebar3 shell
|
||||
Erlang/OTP 25 [erts-13.1.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit] [dtrace]
|
||||
Eshell V13.1.3 (abort with ^G)
|
||||
|
||||
1> Decoded = binary:decode_hex(<<"47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03">>).
|
||||
2> List = binary:bin_to_list(Decoded).
|
||||
3> Hash = binary:list_to_bin(lists:sublist(List, 1, 32)).
|
||||
4> Sig = binary:list_to_bin(lists:sublist(List, 64, 65)).
|
||||
5> Input = <<Hash/binary, 0:(8*31), Sig/binary>>.
|
||||
6> binary:bin_to_list(Input) == binary:bin_to_list(Decoded).
|
||||
7> Result = ecrecover:recover(Hash, Sig).
|
||||
8> Expected = binary:decode_hex(<<"000000000000000000000000c08b5542d177ac6686946920409741463a15dddb">>).
|
||||
9> Result == Expected. %% check result
|
||||
```
|
||||
|
101
c_src/ecrecover.c
Normal file
101
c_src/ecrecover.c
Normal file
@ -0,0 +1,101 @@
|
||||
// Very specific NIF just for key recovery.
|
||||
// Partly from https://github.com/mbrix/libsecp256k1
|
||||
|
||||
#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 not integer 0-3");
|
||||
}
|
||||
|
||||
if (recid < 0 || recid > 3) {
|
||||
error_result(env, "Recovery id invalid 0-3");
|
||||
}
|
||||
|
||||
result = secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &signature, csignature.data, recid);
|
||||
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
|
||||
finished_recpubkey_buf = enif_make_new_binary(env, pubkeylen, &r);
|
||||
|
||||
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 +0,0 @@
|
||||
4717328000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18000000000000000000000000f941ba12e03
|
@ -1 +0,0 @@
|
||||
47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03
|
15
default.nix
15
default.nix
@ -1,8 +1,6 @@
|
||||
let
|
||||
stable = import (fetchTarball { # 19.09
|
||||
url = https://github.com/NixOS/nixpkgs-channels/archive/a22b0189002.tar.gz;
|
||||
sha256 = "0rgd0cbxg9mrzb830hgjlvy134ivpfcnkyhbnlvvn8vl4y20zqmz";
|
||||
}) {};
|
||||
stable = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/860b56be91fb874d48e23a950815969a7b832fbc.tar.gz"
|
||||
){}; # 21.11
|
||||
in {
|
||||
aeternityEnv = stable.stdenv.mkDerivation {
|
||||
name = "ecrecover";
|
||||
@ -10,11 +8,10 @@ in {
|
||||
## base
|
||||
stable.stdenv
|
||||
## erlang
|
||||
stable.erlangR21 # OTP 21.3.5.2
|
||||
## rust, required for building the NIF
|
||||
stable.rustc
|
||||
stable.cargo
|
||||
stable.cmake
|
||||
stable.libtool
|
||||
stable.autoconf
|
||||
stable.automake
|
||||
stable.erlangR23 # OTP 23.3.4.4
|
||||
];
|
||||
};
|
||||
}
|
||||
|
@ -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
|
38
rebar.config
38
rebar.config
@ -1,17 +1,31 @@
|
||||
{deps, [
|
||||
%% ecrecover prebuilt libraries
|
||||
{ecrecoverprebuilt,
|
||||
{ecrecoverprebuilt_app_with_priv_from_git,
|
||||
{git, "https://github.com/aeternity/ecrecover-prebuilt.git",
|
||||
{ref, "4027374"}}}}
|
||||
]}.
|
||||
{deps,
|
||||
[{sha3, {git, "https://github.com/aeternity/erlang-sha3", {ref, "b5f27a2"}}}]}.
|
||||
|
||||
{plugins, [{rebar_ecrecoverprebuilt_dep,
|
||||
{git, "https://github.com/aeternity/rebar3-ecrecover-prebuilt-plugin.git",
|
||||
{ref, "7286efd"}}}
|
||||
]}.
|
||||
{pre_hooks, [ {compile, "./secp256k1.sh"} ]}.
|
||||
|
||||
{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"}
|
||||
|
||||
, {"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]},
|
||||
{plt_apps, all_deps},
|
||||
{base_plt_apps, [erts, kernel, stdlib, crypto]}
|
||||
{base_plt_apps, [erts, kernel, stdlib]}
|
||||
]}.
|
||||
|
17
rebar.lock
17
rebar.lock
@ -1,5 +1,12 @@
|
||||
[{<<"ecrecoverprebuilt">>,
|
||||
{ecrecoverprebuilt_app_with_priv_from_git,
|
||||
{git,"https://github.com/aeternity/ecrecover-prebuilt.git",
|
||||
{ref,"402737411420fc4c500e1f42c921ef185a35cc56"}}},
|
||||
0}].
|
||||
{"1.2.0",
|
||||
[{<<"hex2bin">>,{pkg,<<"hex2bin">>,<<"1.0.0">>},1},
|
||||
{<<"sha3">>,
|
||||
{git,"https://github.com/aeternity/erlang-sha3",
|
||||
{ref,"b5f27a29ba1179e5907c50d7ec7aa79b2857e981"}},
|
||||
0}]}.
|
||||
[
|
||||
{pkg_hash,[
|
||||
{<<"hex2bin">>, <<"AAC26EAB998AE80EACEE1C7607C629AB503EBF77A62B9242BAE2B94D47DCB71E">>}]},
|
||||
{pkg_hash_ext,[
|
||||
{<<"hex2bin">>, <<"E7012D1D9AADD26E680F0983D26FB8923707F05FAC9688F19F530FA3795E716F">>}]}
|
||||
].
|
||||
|
13
secp256k1.sh
Executable file
13
secp256k1.sh
Executable file
@ -0,0 +1,13 @@
|
||||
#! /bin/sh
|
||||
|
||||
[ -f c_src/secp256k1/.libs/libsecp256k1.a ] && exit 0
|
||||
|
||||
cd c_src
|
||||
git clone https://github.com/bitcoin/secp256k1
|
||||
cd secp256k1
|
||||
git -c advice.detachedHead=false checkout cbe41ac138bc0773d60ab1942b7ad6fc5eccfc19
|
||||
./autogen.sh
|
||||
CFLAGS="-fPIC" ./configure --enable-module-recovery
|
||||
make clean
|
||||
make
|
||||
|
@ -5,7 +5,7 @@
|
||||
{applications,
|
||||
[kernel,
|
||||
stdlib,
|
||||
ecrecoverprebuilt
|
||||
sha3
|
||||
]},
|
||||
{env,[]},
|
||||
{modules, []},
|
||||
|
@ -1,7 +1,7 @@
|
||||
-module(ecrecover).
|
||||
|
||||
%% API
|
||||
-export([recover/2]).
|
||||
-export([recover/2, recover/3]).
|
||||
|
||||
%% NIF
|
||||
-export([load/0]).
|
||||
@ -11,14 +11,11 @@
|
||||
%% NIF API
|
||||
|
||||
load() ->
|
||||
% Prefer locally built NIF (good for testing and exotic platforms) over
|
||||
% prebuilt binaries.
|
||||
case load_local_nif() of
|
||||
ok ->
|
||||
ok;
|
||||
{error, _} ->
|
||||
load_prebuilt_nif()
|
||||
end.
|
||||
EbinDir = filename:dirname(code:which(?MODULE)),
|
||||
AppDir = filename:dirname(EbinDir),
|
||||
PrivDir = filename:join(AppDir, "priv"),
|
||||
SoName = filename:join(PrivDir, atom_to_list(?MODULE)),
|
||||
erlang:load_nif(SoName, 0).
|
||||
|
||||
not_loaded(Line) ->
|
||||
erlang:nif_error({error, {not_loaded, [{module, ?MODULE}, {line, Line}]}}).
|
||||
@ -27,35 +24,24 @@ not_loaded(Line) ->
|
||||
%% External API
|
||||
|
||||
-spec recover(<<_:(32*8)>>, <<_:(65*8)>>) -> <<_:(32*8)>>.
|
||||
recover(<<_:32/binary>> = Hash, <<_:65/binary>> = Sig) ->
|
||||
Input = <<Hash/binary, 0:(8*31), Sig/binary>>,
|
||||
case recover_(Input) of
|
||||
{ok, []} ->
|
||||
<<0:256>>;
|
||||
{ok, Res} ->
|
||||
erlang:list_to_binary(Res);
|
||||
_Err ->
|
||||
recover(Hash, <<V, Sig:64/binary>>) when V == 27; V == 28 ->
|
||||
RecId = V - 27,
|
||||
case recover(Hash, Sig, RecId) of
|
||||
{ok, <<4, XY:64/binary>>} ->
|
||||
<<_:12/bytes, ShortPub:20/bytes>> = keccak256(XY),
|
||||
<<0:96, ShortPub/binary>>;
|
||||
{error, _} ->
|
||||
<<0:256>>
|
||||
end.
|
||||
end;
|
||||
recover(_Hash, _VSig) ->
|
||||
<<0:256>>.
|
||||
|
||||
-spec recover(<<_:(32*8)>>, <<_:(64*8)>>, integer()) -> <<_:(32*8)>>.
|
||||
recover(_Hash, _Sig, _RecId) ->
|
||||
not_loaded(?LINE).
|
||||
|
||||
%%=============================================================================
|
||||
%% Internal Functions
|
||||
|
||||
load_local_nif() ->
|
||||
EbinDir = filename:dirname(code:which(?MODULE)),
|
||||
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).
|
||||
keccak256(Bin) ->
|
||||
sha3:hash(256, Bin).
|
||||
|
@ -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