Merge pull request #17 from aeternity/sh-switch-to-c-nif

Switch to c nif
This commit is contained in:
seanhinde 2023-05-29 13:03:09 +02:00 committed by GitHub
commit ea35734a06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 274 additions and 2297 deletions

View File

@ -1,5 +0,0 @@
[target.'cfg(target_os = "macos")']
rustflags = [
"-C", "link-arg=-undefined",
"-C", "link-arg=dynamic_lookup",
]

View File

@ -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
View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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"]

View File

@ -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
View 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

View File

@ -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
View 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);

View File

@ -1 +0,0 @@
4717328000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18000000000000000000000000f941ba12e03

View File

@ -1 +0,0 @@
47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03

View File

@ -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
];
};
}

View File

@ -1,7 +0,0 @@
#if !defined __AE__BASE64_H
#define __AE__BASE64_H
char *bin2hex(unsigned char*, int);
unsigned char *hex2bin(const char*);
#endif

View File

@ -1,6 +0,0 @@
#if !defined __AE_ECRECOVER_H
#define __AE_ECRECOVER_H
int ecrecover(const unsigned char *input, unsigned char *output);
#endif

View File

@ -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"

View File

@ -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

View File

@ -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]}
]}.

View File

@ -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">>}]}
].

BIN
rebar3

Binary file not shown.

13
secp256k1.sh Executable file
View 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

View File

@ -5,7 +5,7 @@
{applications,
[kernel,
stdlib,
ecrecoverprebuilt
sha3
]},
{env,[]},
{modules, []},

View File

@ -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).

View File

@ -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]).

View File

@ -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
View 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).