From 5ca237202e3c63ce86dafa00a9538283f1abc631 Mon Sep 17 00:00:00 2001 From: John Newby Date: Fri, 2 Aug 2019 15:55:46 +0200 Subject: [PATCH] Erlang integration (basic) done. Docs updated --- Makefile | 21 +++++++-- README.md | 5 +- data/erl_ecrecover.input-fail.bin | 1 + data/erl_ecrecover.input.bin | 1 + include/base64.h | 7 +++ include/ecrecover.h | 6 ++- include/erl_comm.h | 20 ++++++++ src/base64.c | 77 +++++++++++++++++++++++++++++++ src/ecrecover.erl | 45 ++++++++++++++++++ src/erl_comm.c | 63 +++++++++++++++++++++++++ src/erl_ecrecover.c | 45 ++++++++++++++++++ src/lib.rs | 6 ++- src/test.c | 75 +----------------------------- 13 files changed, 290 insertions(+), 82 deletions(-) create mode 100644 data/erl_ecrecover.input-fail.bin create mode 100644 data/erl_ecrecover.input.bin create mode 100644 include/base64.h create mode 100644 include/erl_comm.h create mode 100644 src/base64.c create mode 100644 src/ecrecover.erl create mode 100644 src/erl_comm.c create mode 100644 src/erl_ecrecover.c diff --git a/Makefile b/Makefile index 74dfd6c..54e8e6a 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,26 @@ +DEBUG ?= 0 +ifeq ($(DEBUG), 1) + CFLAGS =-DDEBUG=1 +else + CFLAGS=-DNDEBUG +endif CC = gcc LIBS = -llibecrecover.so LDPATH = -Ltarget/debug +INCLUDEPATH = -Iinclude %.o: %.c $(DEPS) - $(CC) -c -o $@ $< + $(CC) $(CFLAGS) -c -o $(INCLUDEPATH) $@ $< +all: test erl_ecrecover - -test: src/test.c target/debug/libecrecover.so - $(CC) -o $@ $^ $(CFLAGS) $(LDPATH) +test: src/test.c src/base64.c target/debug/libecrecover.so + $(CC) -o $@ $^ $(INCLUDEPATH) $(CFLAGS) $(LDPATH) ./test + +erl_ecrecover: src/erl_ecrecover.c src/base64.c src/erl_comm.c target/debug/libecrecover.so + $(CC) -o$ $@ $^ $(INCLUDEPATH) $(CFLAGS) $(LDPATH) + +clean: + rm -f erl_ecrecover test diff --git a/README.md b/README.md index d55e69a..56b38d3 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,14 @@ # ecrecover -FFI export of Ethereum's ecrecover +FFI export of Ethereum's ecrecover, with Erlang integration. prerequisite: - a checked out copy of my fork of parity-ethereum (https://github.com/johnsnewby/parity-ethereum) checked out in the same directory this is (i.e. it will be referenced as `../parity-ethereum`) to compile: `cargo build` +`make` (automatically runs tests). to test: -`make` (requires gcc) +`make test` (requires gcc) (if you don't see `Test passed` then something went wrong). \ No newline at end of file diff --git a/data/erl_ecrecover.input-fail.bin b/data/erl_ecrecover.input-fail.bin new file mode 100644 index 0000000..dba9420 --- /dev/null +++ b/data/erl_ecrecover.input-fail.bin @@ -0,0 +1 @@ +4717328000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18000000000000000000000000f941ba12e03 \ No newline at end of file diff --git a/data/erl_ecrecover.input.bin b/data/erl_ecrecover.input.bin new file mode 100644 index 0000000..fb70f83 --- /dev/null +++ b/data/erl_ecrecover.input.bin @@ -0,0 +1 @@ +47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03 \ No newline at end of file diff --git a/include/base64.h b/include/base64.h new file mode 100644 index 0000000..3dad595 --- /dev/null +++ b/include/base64.h @@ -0,0 +1,7 @@ +#if !defined __AE__BASE64_H +#define __AE__BASE64_H + +char *bin2hex(unsigned char*, int); +unsigned char *hex2bin(const char*); + +#endif diff --git a/include/ecrecover.h b/include/ecrecover.h index fc53f50..bfd57b6 100644 --- a/include/ecrecover.h +++ b/include/ecrecover.h @@ -1,2 +1,6 @@ +#if !defined __AE_ECRECOVER_H +#define __AE_ECRECOVER_H -void ecrecover(const unsigned char *input, unsigned char *output); +int ecrecover(const unsigned char *input, unsigned char *output); + +#endif diff --git a/include/erl_comm.h b/include/erl_comm.h new file mode 100644 index 0000000..d756d69 --- /dev/null +++ b/include/erl_comm.h @@ -0,0 +1,20 @@ +#if !defined __AE__ERL_COMM_H +#define __AE__ERL_COMM_H + +#ifdef DEBUG +#include +#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 diff --git a/src/base64.c b/src/base64.c new file mode 100644 index 0000000..59749b3 --- /dev/null +++ b/src/base64.c @@ -0,0 +1,77 @@ +#include "base64.h" + +#include + + +char *bin2hex(unsigned char *p, int len) +{ + char *hex = malloc(((2*len) + 1)); + char *r = hex; + + while(len && p) + { + (*r) = ((*p) & 0xF0) >> 4; + (*r) = ((*r) <= 9 ? '0' + (*r) : 'a' - 10 + (*r)); + r++; + (*r) = ((*p) & 0x0F); + (*r) = ((*r) <= 9 ? '0' + (*r) : 'a' - 10 + (*r)); + r++; + p++; + len--; + } + *r = '\0'; + + return hex; +} + +unsigned char *hex2bin(const char *str) +{ + int len, h; + unsigned char *result, *err, *p, c; + + err = malloc(1); + *err = 0; + + if (!str) + return err; + + if (!*str) + return err; + + len = 0; + p = (unsigned char*) str; + while (*p++) + len++; + + result = malloc((len/2)+1); + h = !(len%2) * 4; + p = result; + *p = 0; + + c = *str; + while(c) + { + if(('0' <= c) && (c <= '9')) + *p += (c - '0') << h; + else if(('A' <= c) && (c <= 'F')) + *p += (c - 'A' + 10) << h; + else if(('a' <= c) && (c <= 'f')) + *p += (c - 'a' + 10) << h; + else + return err; + + str++; + c = *str; + + if (h) + h = 0; + else + { + h = 4; + p++; + *p = 0; + } + } + + return result; +} diff --git a/src/ecrecover.erl b/src/ecrecover.erl new file mode 100644 index 0000000..91f324e --- /dev/null +++ b/src/ecrecover.erl @@ -0,0 +1,45 @@ +-module(ecrecover). +-export([start/1, stop/0, init/1]). +-export([ecrecover/1]). + +start(ExtPrg) -> + spawn(?MODULE, init, [ExtPrg]). +stop() -> + ecrecover ! stop. + +ecrecover(X) -> + call_port({ecrecover, X}). + +call_port(Msg) -> + ecrecover ! {call, self(), Msg}, + receive + {ecrecover, Result} -> + Result + end. + +init(ExtPrg) -> + register(ecrecover, self()), + process_flag(trap_exit, true), + Port = open_port({spawn, ExtPrg}, [{packet, 2}]), + loop(Port). + +loop(Port) -> + receive + {call, Caller, Msg} -> + Port ! {self(), {command, encode(Msg)}}, + receive + {Port, {data, Data}} -> + Caller ! {ecrecover, Data} + end, + loop(Port); + stop -> + Port ! {self(), close}, + receive + {Port, closed} -> + exit(normal) + end; + {'EXIT', Port, _} -> + exit(port_terminated) + end. + +encode({_, X}) -> [1, X]. diff --git a/src/erl_comm.c b/src/erl_comm.c new file mode 100644 index 0000000..4e174c3 --- /dev/null +++ b/src/erl_comm.c @@ -0,0 +1,63 @@ +// -*- C -*- + +#include "erl_comm.h" + +#include + +int read_cmd(byte *buf) +{ + int len; + + if (read_exact(buf, 2) != 2) + return(-1); + len = (buf[0] << 8) | buf[1]; + DEBUG_PRINTF("Len is %d\n", len); + if(len > ECRECOVER_BUFFER_MAX - 1) { + DEBUG_PRINTF("Avoiding overflow\n"); + return 0; // let's not overflow. + } + int read = read_exact(buf, len); + DEBUG_PRINTF("read_cmd returning %d\n", read); + return read; +} + +int write_cmd(byte *buf, int len) +{ + byte li; + + li = (len >> 8) & 0xff; + write_exact(&li, 1); + + li = len & 0xff; + write_exact(&li, 1); + + return write_exact(buf, len); +} + +int read_exact(byte *buf, int len) +{ + int i, got=0; + DEBUG_PRINTF("Read exact\n"); + do { + if ((i = read(0, buf+got, len-got)) <= 0) { + DEBUG_PRINTF("got=%d len=%d i=%d\n", got, len, i); + return(i); + } + got += i; + } while (got +#include +#include +#include + +#include "ecrecover.h" +#include "erl_comm.h" +#include "base64.h" + +#define OUTPUT_LENGTH 32 + +int main(int arc, char **argv) +{ + int fn, arg, len; + byte buf[ECRECOVER_BUFFER_MAX]; + + while ((len = read_cmd(buf)) > 0) { + DEBUG_PRINTF("len %d\n", len); + fn = buf[0]; + DEBUG_PRINTF("Function %d len %d\n", fn, len); + buf[len] = '\0'; + if (fn == 1) { + int result; + byte *input = hex2bin(buf+1); + byte *output = malloc(ECRECOVER_BUFFER_MAX); + result = ecrecover(input, output); + free(input); + DEBUG_PRINTF("Return value is %d", result); + if(result) { + byte *hex_result = bin2hex(output, OUTPUT_LENGTH); + strcpy(buf, hex_result); + free(hex_result); + DEBUG_PRINTF("result is %s len %ld\n", buf, strlen(buf)); + } else { + strcpy("failed", buf); + } + free(output); + } else { + strcpy("function not found", buf); + } + DEBUG_PRINTF("Returning %s\n", buf); + write_cmd(buf, strlen(buf)); + } +} diff --git a/src/lib.rs b/src/lib.rs index ccd6751..f65f203 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,13 +14,17 @@ const INPUT_LENGTH: usize = 512; const OUTPUT_LENGTH: usize = 32; #[no_mangle] -pub unsafe extern "C" fn ecrecover(input: *const libc::c_uchar, output: *mut libc::c_uchar) { +pub unsafe extern "C" fn ecrecover(input: *const libc::c_uchar, output: *mut libc::c_uchar) -> i16 { let ecrecover = EcRecover { }; let mut byte_ref = Vec::new(); ecrecover.execute(unsafe { std::slice::from_raw_parts(input as *const u8, INPUT_LENGTH) }, &mut BytesRef::Flexible(&mut byte_ref)); let mut ptr: &mut[u8] = unsafe { std::slice::from_raw_parts_mut(output as *mut u8, OUTPUT_LENGTH) }; + if byte_ref.len() != OUTPUT_LENGTH { + return 0; + } ptr.copy_from_slice(byte_ref.as_slice()); + return 1; } #[cfg(test)] diff --git a/src/test.c b/src/test.c index 266caae..26f6527 100644 --- a/src/test.c +++ b/src/test.c @@ -1,4 +1,4 @@ -// -*- C -*- +// -*-C-*- #include #include #include @@ -21,76 +21,3 @@ int main(int arc, char **argv) assert(strcmp(bin2hex(output, OUTPUT_LENGTH), expected) == 0); printf("Test passed\n"); } - -char *bin2hex(unsigned char *p, int len) -{ - char *hex = malloc(((2*len) + 1)); - char *r = hex; - - while(len && p) - { - (*r) = ((*p) & 0xF0) >> 4; - (*r) = ((*r) <= 9 ? '0' + (*r) : 'a' - 10 + (*r)); - r++; - (*r) = ((*p) & 0x0F); - (*r) = ((*r) <= 9 ? '0' + (*r) : 'a' - 10 + (*r)); - r++; - p++; - len--; - } - *r = '\0'; - - return hex; -} - -unsigned char *hex2bin(const char *str) -{ - int len, h; - unsigned char *result, *err, *p, c; - - err = malloc(1); - *err = 0; - - if (!str) - return err; - - if (!*str) - return err; - - len = 0; - p = (unsigned char*) str; - while (*p++) - len++; - - result = malloc((len/2)+1); - h = !(len%2) * 4; - p = result; - *p = 0; - - c = *str; - while(c) - { - if(('0' <= c) && (c <= '9')) - *p += (c - '0') << h; - else if(('A' <= c) && (c <= 'F')) - *p += (c - 'A' + 10) << h; - else if(('a' <= c) && (c <= 'f')) - *p += (c - 'a' + 10) << h; - else - return err; - - str++; - c = *str; - - if (h) - h = 0; - else - { - h = 4; - p++; - *p = 0; - } - } - - return result; -}