Skip to content
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

PoC: Add hazmat module (exposing scalar, point) #1635

Open
wants to merge 2 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ ecdsa_example
schnorr_example
ellswift_example
musig_example
hazmat_example
*.exe
*.so
*.a
Expand Down
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,14 @@ option(SECP256K1_ENABLE_MODULE_EXTRAKEYS "Enable extrakeys module." ON)
option(SECP256K1_ENABLE_MODULE_SCHNORRSIG "Enable schnorrsig module." ON)
option(SECP256K1_ENABLE_MODULE_MUSIG "Enable musig module." ON)
option(SECP256K1_ENABLE_MODULE_ELLSWIFT "Enable ElligatorSwift module." ON)
option(SECP256K1_ENABLE_MODULE_HAZMAT "Enable hazmat module." OFF)

# Processing must be done in a topological sorting of the dependency graph
# (dependent module first).
if(SECP256K1_ENABLE_MODULE_HAZMAT)
add_compile_definitions(ENABLE_MODULE_HAZMAT=1)
endif()

if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
add_compile_definitions(ENABLE_MODULE_ELLSWIFT=1)
endif()
Expand Down Expand Up @@ -327,6 +332,7 @@ message(" extrakeys ........................... ${SECP256K1_ENABLE_MODULE_EXTRA
message(" schnorrsig .......................... ${SECP256K1_ENABLE_MODULE_SCHNORRSIG}")
message(" musig ............................... ${SECP256K1_ENABLE_MODULE_MUSIG}")
message(" ElligatorSwift ...................... ${SECP256K1_ENABLE_MODULE_ELLSWIFT}")
message(" hazmat .............................. ${SECP256K1_ENABLE_MODULE_HAZMAT}")
message("Parameters:")
message(" ecmult window size .................. ${SECP256K1_ECMULT_WINDOW_SIZE}")
message(" ecmult gen table size ............... ${SECP256K1_ECMULT_GEN_KB} KiB")
Expand Down
15 changes: 15 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,17 @@ musig_example_LDFLAGS += -lbcrypt
endif
TESTS += musig_example
endif
if ENABLE_MODULE_HAZMAT
noinst_PROGRAMS += hazmat_example
hazmat_example_SOURCES = examples/hazmat.c
hazmat_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC
hazmat_example_LDADD = libsecp256k1.la
hazmat_example_LDFLAGS = -static
if BUILD_WINDOWS
hazmat_example_LDFLAGS += -lbcrypt
endif
TESTS += hazmat_example
endif
endif

### Precomputed tables
Expand Down Expand Up @@ -300,3 +311,7 @@ endif
if ENABLE_MODULE_ELLSWIFT
include src/modules/ellswift/Makefile.am.include
endif

if ENABLE_MODULE_HAZMAT
include src/modules/hazmat/Makefile.am.include
endif
10 changes: 10 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ AC_ARG_ENABLE(module_ellswift,
AS_HELP_STRING([--enable-module-ellswift],[enable ElligatorSwift module [default=yes]]), [],
[SECP_SET_DEFAULT([enable_module_ellswift], [yes], [yes])])

AC_ARG_ENABLE(module_hazmat,
AS_HELP_STRING([--enable-module-hazmat],[enable hazmat module [default=no]]), [],
[SECP_SET_DEFAULT([enable_module_hazmat], [no], [yes])])

AC_ARG_ENABLE(external_default_callbacks,
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [],
[SECP_SET_DEFAULT([enable_external_default_callbacks], [no], [no])])
Expand Down Expand Up @@ -430,6 +434,10 @@ if test x"$enable_module_ecdh" = x"yes"; then
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDH=1"
fi

if test x"$enable_module_hazmat" = x"yes"; then
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_HAZMAT=1"
fi

if test x"$enable_external_default_callbacks" = x"yes"; then
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_EXTERNAL_DEFAULT_CALLBACKS=1"
fi
Expand Down Expand Up @@ -463,6 +471,7 @@ AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"
AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_MUSIG], [test x"$enable_module_musig" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_ELLSWIFT], [test x"$enable_module_ellswift" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_HAZMAT], [test x"$enable_module_hazmat" = x"yes"])
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$enable_external_asm" = x"yes"])
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm32"])
AM_CONDITIONAL([BUILD_WINDOWS], [test "$build_windows" = "yes"])
Expand All @@ -486,6 +495,7 @@ echo " module extrakeys = $enable_module_extrakeys"
echo " module schnorrsig = $enable_module_schnorrsig"
echo " module musig = $enable_module_musig"
echo " module ellswift = $enable_module_ellswift"
echo " module hazmat = $enable_module_hazmat"
echo
echo " asm = $set_asm"
echo " ecmult window size = $set_ecmult_window"
Expand Down
4 changes: 4 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,7 @@ endif()
if(SECP256K1_ENABLE_MODULE_MUSIG)
add_example(musig)
endif()

if(SECP256K1_ENABLE_MODULE_HAZMAT)
add_example(hazmat)
endif()
196 changes: 196 additions & 0 deletions examples/hazmat.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
/*************************************************************************
* To the extent possible under law, the author(s) have dedicated all *
* copyright and related and neighboring rights to the software in this *
* file to the public domain worldwide. This software is distributed *
* without any warranty. For the CC0 Public Domain Dedication, see *
* EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
*************************************************************************/

#include <assert.h>
#include <stdio.h>
#include <string.h>

#include <secp256k1.h>
#include <secp256k1_hazmat.h>

#include "examples_util.h"

int main(void) {
secp256k1_context* ctx;
unsigned char randomize[32];
secp256k1_hazmat_scalar a[3], a_sum;
secp256k1_hazmat_point A[3], A_sum;
unsigned char lhs_ser[33], rhs_ser[33];
int return_val, i;

/* Create a secp256k1 context
* Note that in the hazmat module, the context is only needed for multiplication
* with the generator point (function `secp256k1_hazmat_multiply_with_generator`).
*/
ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
if (!fill_random(randomize, sizeof(randomize))) {
printf("Failed to generate randomness\n");
return 1;
}
/* Randomizing the context is recommended to protect against side-channel
* leakage. See `secp256k1_context_randomize` in secp256k1.h for more
* information about it. This should never fail.
*/
return_val = secp256k1_context_randomize(ctx, randomize);
assert(return_val);

/* Generate keypairs */
for (i = 0; i < 3; i++) {
unsigned char scalar_buf[32];
unsigned char point_ser[33];

if (!fill_random(scalar_buf, sizeof(scalar_buf))) {
printf("Failed to generate randomness\n");
return 1;
}
if (!secp256k1_hazmat_scalar_parse(&a[i], scalar_buf) || secp256k1_hazmat_scalar_is_zero(&a[i])) {
printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n");
return 1;
}
secp256k1_hazmat_multiply_with_generator(ctx, &A[i], &a[i]);

secp256k1_hazmat_point_serialize(point_ser, &A[i]);
printf("scalar a_%d: ", i+1); print_hex(scalar_buf, sizeof(scalar_buf));
printf("point A_%d: ", i+1); print_hex(point_ser, sizeof(point_ser));

secure_erase(scalar_buf, sizeof(scalar_buf));
}

/* Simple example: verify that (a_1 + a_2 + a_3) * G = A_1 + A_2 + A_3 holds */
secp256k1_hazmat_scalar_set_zero(&a_sum);
secp256k1_hazmat_point_set_infinity(&A_sum);
for (i = 0; i < 3; i++) {
secp256k1_hazmat_scalar_add(&a_sum, &a_sum, &a[i]);
secp256k1_hazmat_point_add(&A_sum, &A_sum, &A[i]);
}

{
secp256k1_hazmat_point A_lhs;

secp256k1_hazmat_multiply_with_generator(ctx, &A_lhs, &a_sum);
secp256k1_hazmat_point_serialize(lhs_ser, &A_lhs);
secp256k1_hazmat_point_serialize(rhs_ser, &A_sum);

printf("\n");
printf("(a_1 + a_2 + a_3) * G: ");
print_hex(lhs_ser, sizeof(lhs_ser));
printf(" A_1 + A_2 + A_3: ");
print_hex(rhs_ser, sizeof(rhs_ser));

/* Verify equality for both the hazmat points and their serialization */
return_val = secp256k1_hazmat_point_equal(&A_lhs, &A_sum);
assert(return_val == 1);
return_val = memcmp(lhs_ser, rhs_ser, sizeof(lhs_ser));
assert(return_val == 0);
}

/* Next example: verify that a_1 * A_2 = A_1 * a_2 (ECDH) */
{
secp256k1_hazmat_point lhs, rhs;

secp256k1_hazmat_multiply_with_point(&lhs, &a[0], &A[1]);
secp256k1_hazmat_multiply_with_point(&rhs, &a[1], &A[0]);
secp256k1_hazmat_point_serialize(lhs_ser, &lhs);
secp256k1_hazmat_point_serialize(rhs_ser, &rhs);

printf("\n");
printf(" a_1 * A_2: ");
print_hex(lhs_ser, sizeof(lhs_ser));
printf(" A_1 * a_2: ");
print_hex(rhs_ser, sizeof(rhs_ser));

return_val = secp256k1_hazmat_point_equal(&lhs, &rhs);
assert(return_val == 1);
return_val = memcmp(lhs_ser, rhs_ser, sizeof(lhs_ser));
assert(return_val == 0);
}

/* Yet another example, to demonstrate also scalar multiplication:
* verify that (a_1 * a_2) * A_3 = a_1 * (a_2 * A_3) */
{
secp256k1_hazmat_point lhs, rhs;
secp256k1_hazmat_scalar tmp_scalar;
secp256k1_hazmat_point tmp_point;

secp256k1_hazmat_scalar_mul(&tmp_scalar, &a[0], &a[1]);
secp256k1_hazmat_multiply_with_point(&lhs, &tmp_scalar, &A[2]);
secp256k1_hazmat_multiply_with_point(&tmp_point, &a[1], &A[2]);
secp256k1_hazmat_multiply_with_point(&rhs, &a[0], &tmp_point);
secp256k1_hazmat_point_serialize(lhs_ser, &lhs);
secp256k1_hazmat_point_serialize(rhs_ser, &rhs);

printf("\n");
printf("(a_1 * a_2) * A_3: ");
print_hex(lhs_ser, sizeof(lhs_ser));
printf(" a_1 * (a_2 * A_3): ");
print_hex(rhs_ser, sizeof(rhs_ser));

return_val = secp256k1_hazmat_point_equal(&lhs, &rhs);
assert(return_val == 1);
return_val = memcmp(lhs_ser, rhs_ser, sizeof(lhs_ser));
assert(return_val == 0);
}

/* Show negation and neutral elements for scalars and points:
* a_i - a_i = 0
* A_i - A_i = point at infinity
*/
for (i = 0; i < 3; i++) {
secp256k1_hazmat_scalar a_result, a_negated;
secp256k1_hazmat_point A_result, A_negated;

a_negated = a[i];
secp256k1_hazmat_scalar_negate(&a_negated);
secp256k1_hazmat_scalar_add(&a_result, &a[i], &a_negated);
assert(secp256k1_hazmat_scalar_is_zero(&a_result));

A_negated = A[i];
secp256k1_hazmat_point_negate(&A_negated);
secp256k1_hazmat_point_add(&A_result, &A[i], &A_negated);
assert(secp256k1_hazmat_point_is_infinity(&A_result));
}

/* To demonstrate parsing points and scalars, verify that the discrete log
* of the generator point is the scalar with value 1. */
{
secp256k1_hazmat_point generator, generator_calculated;
secp256k1_hazmat_scalar scalar_one;
unsigned char generator_ser[33] =
"\x02\x79\xBE\x66\x7E\xF9\xDC\xBB\xAC\x55\xA0\x62\x95\xCE\x87\x0B\x07"
"\x02\x9B\xFC\xDB\x2D\xCE\x28\xD9\x59\xF2\x81\x5B\x16\xF8\x17\x98";
unsigned char scalar_one_ser[32] =
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01";
unsigned char generator_calculated_ser[33];

return_val = secp256k1_hazmat_point_parse(&generator, generator_ser);
assert(return_val);
return_val = secp256k1_hazmat_scalar_parse(&scalar_one, scalar_one_ser);
assert(return_val);
secp256k1_hazmat_multiply_with_generator(ctx, &generator_calculated, &scalar_one);
secp256k1_hazmat_point_serialize(generator_calculated_ser, &generator_calculated);
return_val = secp256k1_hazmat_point_equal(&generator, &generator_calculated);
assert(return_val == 1);
return_val = memcmp(generator_ser, generator_calculated_ser, sizeof(generator_ser));
assert(return_val == 0);
}

/* It's best practice to try to clear secrets from memory after using them.
* This is done because some bugs can allow an attacker to leak memory, for
* example through "out of bounds" array access (see Heartbleed), or the OS
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
*
* Here we are preventing these writes from being optimized out, as any good compiler
* will remove any writes that aren't used. */
for (i = 0; i < 3; i++) {
secure_erase(&a[i], sizeof(a[i]));
}
secure_erase(&a_sum, sizeof(a_sum));

return 0;
}
54 changes: 54 additions & 0 deletions include/secp256k1_hazmat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#ifndef SECP256K1_HAZMAT_H
#define SECP256K1_HAZMAT_H

#include "secp256k1.h"

#ifdef __cplusplus
extern "C" {
#endif

#include <stdint.h>

/* This module provides low-level cryptographic primitives of secp256k1.
* Note that these can be used incorrectly and require an in-depth knowledge
* of the cryptographic concepts at work, therefore we call this the
* "hazardous materials" library or "hazmat" for short.
*/

/* Scalar */
typedef union {
unsigned char data[32];
uint64_t align8; /* ensure alignment on 8-bytes boundaries */
} secp256k1_hazmat_scalar;

SECP256K1_API int secp256k1_hazmat_scalar_parse(secp256k1_hazmat_scalar *s, const unsigned char *bin32);
SECP256K1_API void secp256k1_hazmat_scalar_serialize(unsigned char *bin32, const secp256k1_hazmat_scalar *s);
SECP256K1_API void secp256k1_hazmat_scalar_set_zero(secp256k1_hazmat_scalar *s);
SECP256K1_API int secp256k1_hazmat_scalar_is_zero(const secp256k1_hazmat_scalar *s);
SECP256K1_API void secp256k1_hazmat_scalar_add(secp256k1_hazmat_scalar *sres, const secp256k1_hazmat_scalar *s1, const secp256k1_hazmat_scalar *s2);
SECP256K1_API void secp256k1_hazmat_scalar_mul(secp256k1_hazmat_scalar *sres, const secp256k1_hazmat_scalar *s1, const secp256k1_hazmat_scalar *s2);
SECP256K1_API void secp256k1_hazmat_scalar_negate(secp256k1_hazmat_scalar *s);

/* Point */
typedef union {
unsigned char data[160];
uint64_t align8; /* ensure alignment on 8-bytes boundaries */
} secp256k1_hazmat_point;

SECP256K1_API int secp256k1_hazmat_point_parse(secp256k1_hazmat_point *p, const unsigned char *pubkey33);
SECP256K1_API void secp256k1_hazmat_point_serialize(unsigned char *pubkey33, secp256k1_hazmat_point *p);
SECP256K1_API void secp256k1_hazmat_point_set_infinity(secp256k1_hazmat_point *p);
SECP256K1_API int secp256k1_hazmat_point_is_infinity(const secp256k1_hazmat_point *p);
SECP256K1_API void secp256k1_hazmat_point_add(secp256k1_hazmat_point *pres, secp256k1_hazmat_point *p1, secp256k1_hazmat_point *p2);
SECP256K1_API void secp256k1_hazmat_point_negate(secp256k1_hazmat_point *p);
SECP256K1_API int secp256k1_hazmat_point_equal(const secp256k1_hazmat_point *p1, const secp256k1_hazmat_point *p2);

/* Point multiplication */
SECP256K1_API void secp256k1_hazmat_multiply_with_generator(const secp256k1_context *ctx, secp256k1_hazmat_point *pres, const secp256k1_hazmat_scalar *s);
SECP256K1_API void secp256k1_hazmat_multiply_with_point(secp256k1_hazmat_point *pres, const secp256k1_hazmat_scalar *s, secp256k1_hazmat_point *p);

#ifdef __cplusplus
}
#endif

#endif /* SECP256K1_HAZMAT_H */
3 changes: 3 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ if(SECP256K1_INSTALL)
if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ellswift.h")
endif()
if(SECP256K1_ENABLE_MODULE_HAZMAT)
list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_hazmat.h")
endif()
install(FILES ${${PROJECT_NAME}_headers}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
Expand Down
2 changes: 2 additions & 0 deletions src/modules/hazmat/Makefile.am.include
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
include_HEADERS += include/secp256k1_hazmat.h
noinst_HEADERS += src/modules/hazmat/main_impl.h
Loading