Skip to content

Commit f2cfad7

Browse files
committed
add submodule, build libsecp256k1, add baseline nif
1 parent 81f404e commit f2cfad7

File tree

6 files changed

+200
-2
lines changed

6 files changed

+200
-2
lines changed

apps/arweave/c_src/secp256k1/Makefile

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
ERTS_INCLUDE_DIR ?= $(shell erl -noshell -eval 'io:format("~ts/erts-~ts/include/", [code:root_dir(), erlang:system_info(version)]).' -s init stop)
2+
ERL_INTERFACE_INCLUDE_DIR ?= $(shell erl -noshell -eval 'io:format("~ts", [code:lib_dir(erl_interface, include)]).' -s init stop)
3+
ERL_INTERFACE_LIB_DIR ?= $(shell erl -noshell -eval 'io:format("~ts", [code:lib_dir(erl_interface, lib)]).' -s init stop)
4+
5+
CC = cc
6+
ifeq ($(MODE), debug)
7+
CFLAGS ?= -O0 -g
8+
else
9+
CFLAGS ?= -O3
10+
endif
11+
CFLAGS += -fPIC -shared -I $(ERTS_INCLUDE_DIR) -I $(ERL_INTERFACE_INCLUDE_DIR) -I /usr/local/include -I ../../lib/secp256k1/src -I ../../lib/secp256k1/include
12+
LDFLAGS = -L../../lib/secp256k1/build/lib
13+
LDLIBS = -L $(ERL_INTERFACE_LIB_DIR) -L /usr/local/lib -lsecp256k1
14+
NIF_SRC = secp256k1_nif.c
15+
NIF_SO = $(shell pwd)/../../priv/secp256k1_nif.so
16+
17+
all: $(NIF_SO)
18+
19+
$(NIF_SO): $(NIF_SRC)
20+
$(CC) $(CFLAGS) $(NIF_SRC) -o $(NIF_SO) $(LDFLAGS) $(LDLIBS)
21+
22+
clean:
23+
rm -f $(NIF_SO)
+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*************************************************************************
2+
* Copyright (c) 2020-2021 Elichai Turkel *
3+
* Distributed under the CC0 software license, see the accompanying file *
4+
* EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
5+
*************************************************************************/
6+
7+
/*
8+
* This file is an attempt at collecting best practice methods for obtaining randomness with different operating systems.
9+
* It may be out-of-date. Consult the documentation of the operating system before considering to use the methods below.
10+
*
11+
* Platform randomness sources:
12+
* Linux -> `getrandom(2)`(`sys/random.h`), if not available `/dev/urandom` should be used. http://man7.org/linux/man-pages/man2/getrandom.2.html, https://linux.die.net/man/4/urandom
13+
* macOS -> `getentropy(2)`(`sys/random.h`), if not available `/dev/urandom` should be used. https://www.unix.com/man-page/mojave/2/getentropy, https://opensource.apple.com/source/xnu/xnu-517.12.7/bsd/man/man4/random.4.auto.html
14+
* FreeBSD -> `getrandom(2)`(`sys/random.h`), if not available `kern.arandom` should be used. https://www.freebsd.org/cgi/man.cgi?query=getrandom, https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4
15+
* OpenBSD -> `getentropy(2)`(`unistd.h`), if not available `/dev/urandom` should be used. https://man.openbsd.org/getentropy, https://man.openbsd.org/urandom
16+
* Windows -> `BCryptGenRandom`(`bcrypt.h`). https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
17+
*/
18+
19+
#if defined(_WIN32)
20+
/*
21+
* The defined WIN32_NO_STATUS macro disables return code definitions in
22+
* windows.h, which avoids "macro redefinition" MSVC warnings in ntstatus.h.
23+
*/
24+
#define WIN32_NO_STATUS
25+
#include <windows.h>
26+
#undef WIN32_NO_STATUS
27+
#include <ntstatus.h>
28+
#include <bcrypt.h>
29+
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
30+
#include <sys/random.h>
31+
#elif defined(__OpenBSD__)
32+
#include <unistd.h>
33+
#else
34+
#error "Couldn't identify the OS"
35+
#endif
36+
37+
#include <stddef.h>
38+
#include <limits.h>
39+
#include <stdio.h>
40+
#include <string.h>
41+
42+
/* Returns 1 on success, and 0 on failure. */
43+
static int fill_random(unsigned char* data, size_t size) {
44+
#if defined(_WIN32)
45+
NTSTATUS res = BCryptGenRandom(NULL, data, size, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
46+
if (res != STATUS_SUCCESS || size > ULONG_MAX) {
47+
return 0;
48+
} else {
49+
return 1;
50+
}
51+
#elif defined(__linux__) || defined(__FreeBSD__)
52+
/* If `getrandom(2)` is not available you should fallback to /dev/urandom */
53+
ssize_t res = getrandom(data, size, 0);
54+
if (res < 0 || (size_t)res != size ) {
55+
return 0;
56+
} else {
57+
return 1;
58+
}
59+
#elif defined(__APPLE__) || defined(__OpenBSD__)
60+
/* If `getentropy(2)` is not available you should fallback to either
61+
* `SecRandomCopyBytes` or /dev/urandom */
62+
int res = getentropy(data, size);
63+
if (res == 0) {
64+
return 1;
65+
} else {
66+
return 0;
67+
}
68+
#endif
69+
return 0;
70+
}
71+
72+
static void print_hex(unsigned char* data, size_t size) {
73+
size_t i;
74+
printf("0x");
75+
for (i = 0; i < size; i++) {
76+
printf("%02x", data[i]);
77+
}
78+
printf("\n");
79+
}
80+
81+
#if defined(_MSC_VER)
82+
// For SecureZeroMemory
83+
#include <Windows.h>
84+
#endif
85+
/* Cleanses memory to prevent leaking sensitive info. Won't be optimized out. */
86+
static void secure_erase(void *ptr, size_t len) {
87+
#if defined(_MSC_VER)
88+
/* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */
89+
SecureZeroMemory(ptr, len);
90+
#elif defined(__GNUC__)
91+
/* We use a memory barrier that scares the compiler away from optimizing out the memset.
92+
*
93+
* Quoting Adam Langley <[email protected]> in commit ad1907fe73334d6c696c8539646c21b11178f20f
94+
* in BoringSSL (ISC License):
95+
* As best as we can tell, this is sufficient to break any optimisations that
96+
* might try to eliminate "superfluous" memsets.
97+
* This method used in memzero_explicit() the Linux kernel, too. Its advantage is that it is
98+
* pretty efficient, because the compiler can still implement the memset() efficiently,
99+
* just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by
100+
* Yang et al. (USENIX Security 2017) for more background.
101+
*/
102+
memset(ptr, 0, len);
103+
__asm__ __volatile__("" : : "r"(ptr) : "memory");
104+
#else
105+
void *(*volatile const volatile_memset)(void *, int, size_t) = memset;
106+
volatile_memset(ptr, 0, len);
107+
#endif
108+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#include <secp256k1.h>
2+
3+
#include "../ar_nif.h"
4+
#include "./fill_random.h"
5+
6+
#define SECP256K1_PUBKEY_UNCOMPRESSED_SIZE 65
7+
#define SECP256K1_PUBKEY_COMPRESSED_SIZE 33
8+
#define SECP256K1_PRIVKEY_SIZE 32
9+
#define SECP256K1_CONTEXT_SEED_SIZE 32
10+
11+
static int secp256k1_load(ErlNifEnv* env, void** priv, ERL_NIF_TERM load_info) {
12+
return 0;
13+
}
14+
15+
static ERL_NIF_TERM generate_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
16+
unsigned char seed[SECP256K1_CONTEXT_SEED_SIZE];
17+
if (!fill_random(seed, sizeof(seed))) {
18+
return error_tuple(env, "Failed to generate random seed for context.");
19+
}
20+
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
21+
if (!secp256k1_context_randomize(ctx, seed)) {
22+
return error_tuple(env, "Failed to randomize context.");
23+
}
24+
25+
unsigned char privbytes[SECP256K1_PRIVKEY_SIZE];
26+
if (!fill_random(privbytes, sizeof(privbytes))) {
27+
return error_tuple(env, "Failed to generate random key.");
28+
}
29+
if (!secp256k1_ec_seckey_verify(ctx, privbytes)) {
30+
return error_tuple(env, "Generated secret secp256k1 key is invalid.");
31+
}
32+
33+
secp256k1_pubkey pubkey;
34+
if(!secp256k1_ec_pubkey_create(ctx, &pubkey, privbytes)) {
35+
return error_tuple(env, "Failed to populate public key.");
36+
}
37+
38+
unsigned char pubbytes[SECP256K1_PUBKEY_UNCOMPRESSED_SIZE];
39+
size_t l = sizeof(pubbytes);
40+
if (!secp256k1_ec_pubkey_serialize(ctx, pubbytes, &l, &pubkey, SECP256K1_EC_UNCOMPRESSED)) {
41+
return error_tuple(env, "Failed to serialize public key.");
42+
}
43+
44+
ERL_NIF_TERM privkey_bin = make_output_binary(env, privbytes, SECP256K1_PRIVKEY_SIZE);
45+
ERL_NIF_TERM pubkey_bin = make_output_binary(env, pubbytes, SECP256K1_PUBKEY_UNCOMPRESSED_SIZE);
46+
return ok_tuple2(env, privkey_bin, pubkey_bin);
47+
}

rebar.config

+5-1
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,8 @@
397397
{"(linux)", compile, "make -C apps/arweave/lib/RandomX/buildsquared"},
398398
{"(freebsd|netbsd|openbsd)", compile, "gmake -C apps/arweave/lib/RandomX/buildsquared"},
399399
{"(darwin|linux|freebsd|netbsd|openbsd)", compile, "bash -c \"cd apps/arweave/lib/RandomX/buildsquared && mv librandomx.a librandomxsquared.a\""},
400+
% Build secp256k1
401+
{"(darwin|linux|freebsd|netbsd|openbsd)", compile, "./scripts/build_secp256k1.sh > /dev/null"},
400402
% Compile NIFs
401403
{"(linux)", compile, "env AR=gcc-ar make all -C apps/arweave/c_src"},
402404
{"(darwin)", compile, "make all -C apps/arweave/c_src"},
@@ -412,7 +414,9 @@
412414
% Clean randomxsquared
413415
{"(linux|darwin)", clean, "bash -c \"if [ -d apps/arweave/lib/RandomX/buildsquared ]; then make -C apps/arweave/lib/RandomX/buildsquared clean; fi\""},
414416
{"(freebsd|netbsd|openbsd)", clean, "bash -c \"if [ -d apps/arweave/lib/RandomX/buildsquared ]; then gmake -C apps/arweave/lib/RandomX/buildsquared clean; fi\""},
415-
% Clan NIFs
417+
% Clean secp256k1
418+
{"(linux|darwin|freebsd|netbsd|openbsd)", clean, "bash -c \"if [ -d apps/arweave/lib/secp256k1/build ]; then rm -rf apps/arweave/lib/secp256k1/build; fi\""},
419+
% Clean NIFs
416420
{"(linux|darwin)", clean, "make -C apps/arweave/c_src clean"},
417421
{"(freebsd|netbsd|openbsd)", clean, "gmake -C apps/arweave/c_src clean"}
418422
]}.

scripts/build_secp256k1.sh

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/bin/bash
2+
3+
BUILD_DIR="apps/arweave/lib/secp256k1/build"
4+
CMAKE_OPTIONS="-DBUILD_SHARED_LIBS=OFF \
5+
-DSECP256K1_BUILD_BENCHMARK=OFF \
6+
-DSECP256K1_BUILD_EXHAUSTIVE_TESTS=OFF \
7+
-DSECP256K1_BUILD_TESTS=OFF \
8+
-DSECP256K1_DISABLE_SHARED=ON \
9+
-DSECP256K1_ENABLE_MODULE_MUSIG=OFF \
10+
-DSECP256K1_ENABLE_MODULE_EXTRAKEYS=OFF \
11+
-DSECP256K1_ENABLE_MODULE_ELLSWIFT=OFF \
12+
-DSECP256K1_ENABLE_MODULE_SCHNORRSIG=OFF"
13+
mkdir -p $BUILD_DIR
14+
cd $BUILD_DIR
15+
cmake $CMAKE_OPTIONS ..
16+
cmake --build .

0 commit comments

Comments
 (0)