Skip to content

Commit c4e73d5

Browse files
committed
Add hazmat usage example
1 parent 1123e35 commit c4e73d5

File tree

4 files changed

+212
-0
lines changed

4 files changed

+212
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ ecdsa_example
1212
schnorr_example
1313
ellswift_example
1414
musig_example
15+
hazmat_example
1516
*.exe
1617
*.so
1718
*.a

Makefile.am

+11
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,17 @@ musig_example_LDFLAGS += -lbcrypt
206206
endif
207207
TESTS += musig_example
208208
endif
209+
if ENABLE_MODULE_HAZMAT
210+
noinst_PROGRAMS += hazmat_example
211+
hazmat_example_SOURCES = examples/hazmat.c
212+
hazmat_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC
213+
hazmat_example_LDADD = libsecp256k1.la
214+
hazmat_example_LDFLAGS = -static
215+
if BUILD_WINDOWS
216+
hazmat_example_LDFLAGS += -lbcrypt
217+
endif
218+
TESTS += hazmat_example
219+
endif
209220
endif
210221

211222
### Precomputed tables

examples/CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,7 @@ endif()
2929
if(SECP256K1_ENABLE_MODULE_MUSIG)
3030
add_example(musig)
3131
endif()
32+
33+
if(SECP256K1_ENABLE_MODULE_HAZMAT)
34+
add_example(hazmat)
35+
endif()

examples/hazmat.c

+196
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
/*************************************************************************
2+
* To the extent possible under law, the author(s) have dedicated all *
3+
* copyright and related and neighboring rights to the software in this *
4+
* file to the public domain worldwide. This software is distributed *
5+
* without any warranty. For the CC0 Public Domain Dedication, see *
6+
* EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
7+
*************************************************************************/
8+
9+
#include <assert.h>
10+
#include <stdio.h>
11+
#include <string.h>
12+
13+
#include <secp256k1.h>
14+
#include <secp256k1_hazmat.h>
15+
16+
#include "examples_util.h"
17+
18+
int main(void) {
19+
secp256k1_context* ctx;
20+
unsigned char randomize[32];
21+
secp256k1_hazmat_scalar a[3], a_sum;
22+
secp256k1_hazmat_point A[3], A_sum;
23+
unsigned char lhs_ser[33], rhs_ser[33];
24+
int return_val, i;
25+
26+
/* Create a secp256k1 context
27+
* Note that in the hazmat module, the context is only needed for multiplication
28+
* with the generator point (function `secp256k1_hazmat_multiply_with_generator`).
29+
*/
30+
ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
31+
if (!fill_random(randomize, sizeof(randomize))) {
32+
printf("Failed to generate randomness\n");
33+
return 1;
34+
}
35+
/* Randomizing the context is recommended to protect against side-channel
36+
* leakage. See `secp256k1_context_randomize` in secp256k1.h for more
37+
* information about it. This should never fail.
38+
*/
39+
return_val = secp256k1_context_randomize(ctx, randomize);
40+
assert(return_val);
41+
42+
/* Generate keypairs */
43+
for (i = 0; i < 3; i++) {
44+
unsigned char scalar_buf[32];
45+
unsigned char point_ser[33];
46+
47+
if (!fill_random(scalar_buf, sizeof(scalar_buf))) {
48+
printf("Failed to generate randomness\n");
49+
return 1;
50+
}
51+
if (!secp256k1_hazmat_scalar_parse(&a[i], scalar_buf) || secp256k1_hazmat_scalar_is_zero(&a[i])) {
52+
printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n");
53+
return 1;
54+
}
55+
secp256k1_hazmat_multiply_with_generator(ctx, &A[i], &a[i]);
56+
57+
secp256k1_hazmat_point_serialize(point_ser, &A[i]);
58+
printf("scalar a_%d: ", i+1); print_hex(scalar_buf, sizeof(scalar_buf));
59+
printf("point A_%d: ", i+1); print_hex(point_ser, sizeof(point_ser));
60+
61+
secure_erase(scalar_buf, sizeof(scalar_buf));
62+
}
63+
64+
/* Simple example: verify that (a_1 + a_2 + a_3) * G = A_1 + A_2 + A_3 holds */
65+
secp256k1_hazmat_scalar_set_zero(&a_sum);
66+
secp256k1_hazmat_point_set_infinity(&A_sum);
67+
for (i = 0; i < 3; i++) {
68+
secp256k1_hazmat_scalar_add(&a_sum, &a_sum, &a[i]);
69+
secp256k1_hazmat_point_add(&A_sum, &A_sum, &A[i]);
70+
}
71+
72+
{
73+
secp256k1_hazmat_point A_lhs;
74+
75+
secp256k1_hazmat_multiply_with_generator(ctx, &A_lhs, &a_sum);
76+
secp256k1_hazmat_point_serialize(lhs_ser, &A_lhs);
77+
secp256k1_hazmat_point_serialize(rhs_ser, &A_sum);
78+
79+
printf("\n");
80+
printf("(a_1 + a_2 + a_3) * G: ");
81+
print_hex(lhs_ser, sizeof(lhs_ser));
82+
printf(" A_1 + A_2 + A_3: ");
83+
print_hex(rhs_ser, sizeof(rhs_ser));
84+
85+
/* Verify equality for both the hazmat points and their serialization */
86+
return_val = secp256k1_hazmat_point_equal(&A_lhs, &A_sum);
87+
assert(return_val == 1);
88+
return_val = memcmp(lhs_ser, rhs_ser, sizeof(lhs_ser));
89+
assert(return_val == 0);
90+
}
91+
92+
/* Next example: verify that a_1 * A_2 = A_1 * a_2 (ECDH) */
93+
{
94+
secp256k1_hazmat_point lhs, rhs;
95+
96+
secp256k1_hazmat_multiply_with_point(&lhs, &a[0], &A[1]);
97+
secp256k1_hazmat_multiply_with_point(&rhs, &a[1], &A[0]);
98+
secp256k1_hazmat_point_serialize(lhs_ser, &lhs);
99+
secp256k1_hazmat_point_serialize(rhs_ser, &rhs);
100+
101+
printf("\n");
102+
printf(" a_1 * A_2: ");
103+
print_hex(lhs_ser, sizeof(lhs_ser));
104+
printf(" A_1 * a_2: ");
105+
print_hex(rhs_ser, sizeof(rhs_ser));
106+
107+
return_val = secp256k1_hazmat_point_equal(&lhs, &rhs);
108+
assert(return_val == 1);
109+
return_val = memcmp(lhs_ser, rhs_ser, sizeof(lhs_ser));
110+
assert(return_val == 0);
111+
}
112+
113+
/* Yet another example, to demonstrate also scalar multiplication:
114+
* verify that (a_1 * a_2) * A_3 = a_1 * (a_2 * A_3) */
115+
{
116+
secp256k1_hazmat_point lhs, rhs;
117+
secp256k1_hazmat_scalar tmp_scalar;
118+
secp256k1_hazmat_point tmp_point;
119+
120+
secp256k1_hazmat_scalar_mul(&tmp_scalar, &a[0], &a[1]);
121+
secp256k1_hazmat_multiply_with_point(&lhs, &tmp_scalar, &A[2]);
122+
secp256k1_hazmat_multiply_with_point(&tmp_point, &a[1], &A[2]);
123+
secp256k1_hazmat_multiply_with_point(&rhs, &a[0], &tmp_point);
124+
secp256k1_hazmat_point_serialize(lhs_ser, &lhs);
125+
secp256k1_hazmat_point_serialize(rhs_ser, &rhs);
126+
127+
printf("\n");
128+
printf("(a_1 * a_2) * A_3: ");
129+
print_hex(lhs_ser, sizeof(lhs_ser));
130+
printf(" a_1 * (a_2 * A_3): ");
131+
print_hex(rhs_ser, sizeof(rhs_ser));
132+
133+
return_val = secp256k1_hazmat_point_equal(&lhs, &rhs);
134+
assert(return_val == 1);
135+
return_val = memcmp(lhs_ser, rhs_ser, sizeof(lhs_ser));
136+
assert(return_val == 0);
137+
}
138+
139+
/* Show negation and neutral elements for scalars and points:
140+
* a_i - a_i = 0
141+
* A_i - A_i = point at infinity
142+
*/
143+
for (i = 0; i < 3; i++) {
144+
secp256k1_hazmat_scalar a_result, a_negated;
145+
secp256k1_hazmat_point A_result, A_negated;
146+
147+
a_negated = a[i];
148+
secp256k1_hazmat_scalar_negate(&a_negated);
149+
secp256k1_hazmat_scalar_add(&a_result, &a[i], &a_negated);
150+
assert(secp256k1_hazmat_scalar_is_zero(&a_result));
151+
152+
A_negated = A[i];
153+
secp256k1_hazmat_point_negate(&A_negated);
154+
secp256k1_hazmat_point_add(&A_result, &A[i], &A_negated);
155+
assert(secp256k1_hazmat_point_is_infinity(&A_result));
156+
}
157+
158+
/* To demonstrate parsing points and scalars, verify that the discrete log
159+
* of the generator point is the scalar with value 1. */
160+
{
161+
secp256k1_hazmat_point generator, generator_calculated;
162+
secp256k1_hazmat_scalar scalar_one;
163+
unsigned char generator_ser[33] =
164+
"\x02\x79\xBE\x66\x7E\xF9\xDC\xBB\xAC\x55\xA0\x62\x95\xCE\x87\x0B\x07"
165+
"\x02\x9B\xFC\xDB\x2D\xCE\x28\xD9\x59\xF2\x81\x5B\x16\xF8\x17\x98";
166+
unsigned char scalar_one_ser[32] =
167+
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
168+
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01";
169+
unsigned char generator_calculated_ser[33];
170+
171+
return_val = secp256k1_hazmat_point_parse(&generator, generator_ser);
172+
assert(return_val);
173+
return_val = secp256k1_hazmat_scalar_parse(&scalar_one, scalar_one_ser);
174+
assert(return_val);
175+
secp256k1_hazmat_multiply_with_generator(ctx, &generator_calculated, &scalar_one);
176+
secp256k1_hazmat_point_serialize(generator_calculated_ser, &generator_calculated);
177+
return_val = secp256k1_hazmat_point_equal(&generator, &generator_calculated);
178+
assert(return_val == 1);
179+
return_val = memcmp(generator_ser, generator_calculated_ser, sizeof(generator_ser));
180+
assert(return_val == 0);
181+
}
182+
183+
/* It's best practice to try to clear secrets from memory after using them.
184+
* This is done because some bugs can allow an attacker to leak memory, for
185+
* example through "out of bounds" array access (see Heartbleed), or the OS
186+
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
187+
*
188+
* Here we are preventing these writes from being optimized out, as any good compiler
189+
* will remove any writes that aren't used. */
190+
for (i = 0; i < 3; i++) {
191+
secure_erase(&a[i], sizeof(a[i]));
192+
}
193+
secure_erase(&a_sum, sizeof(a_sum));
194+
195+
return 0;
196+
}

0 commit comments

Comments
 (0)