Skip to content

Upgrade secp256k1 to v0.2.0 #26

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 0 additions & 36 deletions .circleci/config.yml

This file was deleted.

39 changes: 39 additions & 0 deletions .github/workflows/elixir.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

name: Elixir CI

on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]

permissions:
contents: read

jobs:
build:

name: Build and test
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Set up Elixir
uses: erlef/setup-beam@61e01a43a562a89bfc54c7f9a378ff67b03e4a21 # v1.16.0
with:
elixir-version: '1.15.2' # [Required] Define the Elixir version
otp-version: '26.0.2' # [Required] Define the Erlang/OTP version
- name: Restore dependencies cache
uses: actions/cache@v3
with:
path: deps
key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
restore-keys: ${{ runner.os }}-mix-
- name: Install dependencies
run: mix deps.get
- name: Run tests
run: mix test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ deps/
.rebar
doc/
*.tar
.vscode
46 changes: 29 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,45 @@
# Erlang NIF C libsecp256k1 [![CircleCI](https://circleci.com/gh/exthereum/libsecp256k1.svg?style=svg)](https://circleci.com/gh/exthereum/libsecp256k1)
# Erlang NIF C libsecp256k1

============

Bindings for most of the library functionality
Tested with Erlang/OTP 17+

Installation
------------
If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `libsecp256k1` to your list of dependencies in `mix.exs`:

```elixir
def deps do
[{:libsecp256k1, "~> 0.1.9"}]
[
{:libsecp256k1, github: "ljzn/libsecp256k1", tag: "v0.2.2"}
]
end
```

Build and usage steps
---------------------
$ mix compile
$ erl -pa _build/dev/lib/libsecp256k1/ebin/
Privkey = crypto:strong_rand_bytes(32).
{ok, Pubkey} = libsecp256k1:ec_pubkey_create(Privkey, compressed).

Testing
Available Functions
-------
$ mix eunit

Debugging
---------
```
ec_pubkey_create/2
ec_pubkey_decompress/1
ec_pubkey_verify/1
ec_privkey_export/2
ec_privkey_import/1
ec_privkey_tweak_add/2
ec_privkey_tweak_mul/2
ec_pubkey_tweak_add/2
ec_pubkey_tweak_mul/2
ecdsa_sign/4
ecdsa_verify/3
schnorr_sign/2
schnorr_verify/3
ecdsa_sign_compact/4
ecdsa_recover_compact/4
ecdsa_verify_compact/3
sha256/1
dsha256/1
ec_xonly_pubkey_tweak_add/2
```

Library should be statically compiled.
Testing
-------
$ mix test
3 changes: 1 addition & 2 deletions c_src/build_deps.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ case "$1" in

(test -d secp256k1 || git clone https://github.com/bitcoin/secp256k1)

(cd secp256k1 && git reset --hard d33352151699bd7598b868369dace092f7855740 && ./autogen.sh && ./configure --enable-module-recovery && make)
#(cd secp256k1 && ./autogen.sh && ./configure --enable-module-recovery && make)
(cd secp256k1 && git reset --hard v0.2.0 && ./autogen.sh && ./configure --enable-module-recovery && make)
;;
esac
127 changes: 114 additions & 13 deletions c_src/libsecp256k1_nif.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
#include "libsecp256k1-config.h"
#include "secp256k1.c"
#include "include/secp256k1.h"
#include "include/secp256k1_extrakeys.h"
#include "include/secp256k1_schnorrsig.h"
#include "time.h"
#include "testrand_impl.h"
#include "include/secp256k1_recovery.h"

Expand Down Expand Up @@ -131,7 +134,7 @@ rand32(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ERL_NIF_TERM r;
unsigned char* output = enif_make_new_binary(env, 4, &r);
uint32_t v = secp256k1_rand32();
uint32_t v = secp256k1_testrand32();
memcpy(&v, output, 4);
return r;
}
Expand All @@ -141,7 +144,7 @@ rand256(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ERL_NIF_TERM r;
unsigned char* output = enif_make_new_binary(env, 32, &r);
secp256k1_rand256(output);
secp256k1_testrand256(output);
return r;
}

Expand All @@ -165,16 +168,9 @@ ec_seckey_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
}

if (privkey.size != 32) {
return enif_make_badarg(env);
}

secp256k1_scalar_set_b32(&key, b32, &overflow);
if (overflow || secp256k1_scalar_is_zero(&key)) {
return enif_make_int(env, 0);
return error_result(env, "Private key size != 32 bytes");
}

secp256k1_scalar_get_b32(privkey.data, &key);

result = secp256k1_ec_seckey_verify(ctx, privkey.data);
return atom_from_result(env, result);
}
Expand Down Expand Up @@ -342,7 +338,7 @@ ec_privkey_tweak_add(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
privkey_buf = enif_make_new_binary(env, 32, &r);
memcpy(privkey_buf, privkey.data, privkey.size);

result = secp256k1_ec_privkey_tweak_add(ctx, privkey_buf, tweak.data);
result = secp256k1_ec_seckey_tweak_add(ctx, privkey_buf, tweak.data);

if (result == 0) {
return error_result(env, "ec_privkey_tweak_add returned 0");
Expand Down Expand Up @@ -385,6 +381,42 @@ ec_pubkey_tweak_add(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
return ok_result(env, &r);
}

static ERL_NIF_TERM
ec_xonly_pubkey_tweak_add(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ERL_NIF_TERM r;
ErlNifBinary x_only_pubkey, tweak;
unsigned char* output_pubkey_buf;
secp256k1_xonly_pubkey x_only_pubkeyt;
secp256k1_pubkey pubkeyt;
size_t size = 65;

if (!enif_inspect_binary(env, argv[0], &x_only_pubkey)) {
return enif_make_badarg(env);
}

if (!enif_inspect_binary(env, argv[1], &tweak)) {
return enif_make_badarg(env);
}

output_pubkey_buf = enif_make_new_binary(env, size, &r);

if (secp256k1_xonly_pubkey_parse(ctx, &x_only_pubkeyt, x_only_pubkey.data) != 1) {
return enif_make_badarg(env);
};

if (secp256k1_xonly_pubkey_tweak_add(ctx, &pubkeyt, &x_only_pubkeyt, tweak.data) != 1) {
return error_result(env, "ec_xonly_pubkey_tweak_add returned 0");
}

if (secp256k1_ec_pubkey_serialize(ctx, output_pubkey_buf, (size_t *)&size, &pubkeyt,
check_compressed(size)) != 1) {
return error_result(env, "Public key serialize error");
}

return ok_result(env, &r);
}

int check_compressed(size_t Size) {
if (Size == 33) {
return SECP256K1_EC_COMPRESSED;
Expand Down Expand Up @@ -491,10 +523,10 @@ ecdsa_sign(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])

// DER serialization may return a signature under buffer size
// need to delay nif binary allocation
if (secp256k1_ecdsa_signature_serialize_der(ctx, &intermediatesig, &siglen, &signature) != 1) {
if (secp256k1_ecdsa_signature_serialize_der(ctx, intermediatesig, &siglen, &signature) != 1) {
return error_result(env, "ecdsa_signature_serialize returned 0");
}
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature, &intermediatesig, siglen) == 1);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature, intermediatesig, siglen) == 1);
finishedsig = enif_make_new_binary(env, siglen, &r);
memcpy(finishedsig, intermediatesig, siglen);
return ok_result(env, &r);
Expand Down Expand Up @@ -536,6 +568,72 @@ ecdsa_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
return atom_from_result(env, result);
}

static ERL_NIF_TERM
schnorr_sign(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ERL_NIF_TERM r;
ErlNifBinary message, privkey;
int result;
secp256k1_keypair keypair;
secp256k1_pubkey pubkey;
secp256k1_xonly_pubkey xonly_pubkey;
unsigned char sig64[64];
unsigned char* finishedsig;
size_t siglen = 64;

if (!enif_inspect_binary(env, argv[0], &message)) {
return enif_make_badarg(env);
}

if (!enif_inspect_binary(env, argv[1], &privkey)) {
return enif_make_badarg(env);
}

CHECK(secp256k1_keypair_create(ctx, &keypair, privkey.data) == 1);

result = secp256k1_schnorrsig_sign32(ctx, sig64, message.data,
&keypair, NULL);
if (!result) {
return error_result(env, "schnorr_sign returned 0");
}

CHECK(secp256k1_keypair_pub(ctx, &pubkey, &keypair) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pubkey, NULL, &pubkey) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, sig64, message.data, message.size, &xonly_pubkey) == 1);
finishedsig = enif_make_new_binary(env, siglen, &r);
memcpy(finishedsig, sig64, siglen);
return ok_result(env, &r);
}

static ERL_NIF_TERM
schnorr_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary message, rawsignature, rawxonlypubkey;
secp256k1_ecdsa_signature signature;
secp256k1_xonly_pubkey xonly_pubkey;
int result;

if (!enif_inspect_binary(env, argv[0], &message)) {
return enif_make_badarg(env);
}

if (!enif_inspect_binary(env, argv[1], &rawsignature)) {
return enif_make_badarg(env);
}

if (!enif_inspect_binary(env, argv[2], &rawxonlypubkey)) {
return enif_make_badarg(env);
}

if (secp256k1_xonly_pubkey_parse(ctx, &xonly_pubkey, rawxonlypubkey.data) != 1) {
return error_result(env, "X Only Public key invalid");
};

result = secp256k1_schnorrsig_verify(ctx, rawsignature.data, message.data, message.size, &xonly_pubkey);

return atom_from_result(env, result);
}

static ERL_NIF_TERM
ecdsa_sign_compact(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
Expand Down Expand Up @@ -782,10 +880,13 @@ static ErlNifFunc nif_funcs[] = {
{"ec_privkey_import", 1, ec_privkey_import},
{"ec_privkey_tweak_add", 2, ec_privkey_tweak_add},
{"ec_pubkey_tweak_add", 2, ec_pubkey_tweak_add},
{"ec_xonly_pubkey_tweak_add", 2, ec_xonly_pubkey_tweak_add},
{"ec_privkey_tweak_mul", 2, ec_privkey_tweak_mul},
{"ec_pubkey_tweak_mul", 2, ec_pubkey_tweak_mul},
{"ecdsa_sign", 4, ecdsa_sign},
{"ecdsa_verify", 3, ecdsa_verify},
{"schnorr_sign", 2, schnorr_sign},
{"schnorr_verify", 3, schnorr_verify},
{"ecdsa_sign_compact", 4, ecdsa_sign_compact},
{"ecdsa_verify_compact", 3, ecdsa_verify_compact},
{"ecdsa_recover_compact", 4, ecdsa_recover_compact}
Expand Down
Loading