Skip to content

Commit a9f796f

Browse files
committed
Add a ecdh shared secret example
1 parent ddd99eb commit a9f796f

File tree

1 file changed

+101
-0
lines changed

1 file changed

+101
-0
lines changed

examples/ecdh.c

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/**********************************************************************
2+
* Copyright (c) 2020 Elichai Turkel *
3+
* Distributed under the MIT software license, see the accompanying *
4+
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
5+
**********************************************************************/
6+
7+
#include <stdio.h>
8+
#include <assert.h>
9+
#include <string.h>
10+
11+
#include "random.h"
12+
#include "secp256k1.h"
13+
#include "secp256k1_ecdh.h"
14+
15+
16+
void print_hex(unsigned char* data, size_t size) {
17+
size_t i;
18+
printf("0x");
19+
for (i = 0; i < size; i++) {
20+
printf("%02x", data[i]);
21+
}
22+
printf("\n");
23+
}
24+
25+
int main(void) {
26+
unsigned char seckey1[32];
27+
unsigned char seckey2[32];
28+
unsigned char compressed_pubkey1[33];
29+
unsigned char compressed_pubkey2[33];
30+
unsigned char shared_secret1[32];
31+
unsigned char shared_secret2[32];
32+
size_t len;
33+
secp256k1_pubkey pubkey1;
34+
secp256k1_pubkey pubkey2;
35+
/* The docs in secp256k1.h above the `secp256k1_ec_pubkey_create` function say:
36+
* "pointer to a context object, initialized for signing"
37+
* Which is why we create a context for signing(SECP256K1_CONTEXT_SIGN).
38+
* (The docs for `secp256k1_ecdh` don't require any special context, just some context) */
39+
40+
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
41+
while (1) {
42+
if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) {
43+
printf("Failed to generate randomness\n");
44+
return 1;
45+
}
46+
if (secp256k1_ec_seckey_verify(ctx, seckey1) && secp256k1_ec_seckey_verify(ctx, seckey2)) {
47+
break;
48+
}
49+
}
50+
51+
/* Pubkey creation on a valid Context with a verified seckey should never fail */
52+
assert(secp256k1_ec_pubkey_create(ctx, &pubkey1, seckey1));
53+
assert(secp256k1_ec_pubkey_create(ctx, &pubkey2, seckey2));
54+
55+
/* Serialize the pubkey in a compressed form */
56+
len = sizeof(compressed_pubkey1);
57+
secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey1, &len, &pubkey1, SECP256K1_EC_COMPRESSED);
58+
/* Should be the same size as the size of the output */
59+
assert(len == sizeof(compressed_pubkey1));
60+
61+
/* Serialize the pubkey in a compressed form */
62+
len = sizeof(compressed_pubkey2);
63+
secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey2, &len, &pubkey2, SECP256K1_EC_COMPRESSED);
64+
assert(len == sizeof(compressed_pubkey2));
65+
66+
/* Perform ECDH with seckey1 and pubkey2, should never fail with a verified seckey and valid pubkey */
67+
assert(secp256k1_ecdh(ctx, shared_secret1, &pubkey2, seckey1, NULL, NULL));
68+
69+
/* Perform ECDH with seckey2 and pubkey1, should never fail with a verified seckey and valid pubkey */
70+
assert(secp256k1_ecdh(ctx, shared_secret2, &pubkey1, seckey2, NULL, NULL));
71+
72+
/* Both parties should end up with the same shared secret */
73+
assert(memcmp(shared_secret1, shared_secret2, sizeof(shared_secret1)) == 0);
74+
75+
printf("Secret Key1: ");
76+
print_hex(seckey1, sizeof(seckey1));
77+
printf("Compressed Pubkey1: ");
78+
print_hex(compressed_pubkey1, sizeof(compressed_pubkey1));
79+
printf("\nSecret Key2: ");
80+
print_hex(seckey2, sizeof(seckey2));
81+
printf("Compressed Pubkey2: ");
82+
print_hex(compressed_pubkey2, sizeof(compressed_pubkey2));
83+
printf("\nShared Secret: ");
84+
print_hex(shared_secret1, sizeof(shared_secret1));
85+
86+
/* This will clear everything from the context and free the memory */
87+
secp256k1_context_destroy(ctx);
88+
89+
/* It's best practice to try and zero out secrets after using them.
90+
* This is done because some bugs can allow an attacker leak memory, for example out of bounds array access(see Heartbleed for example).
91+
* We want to prevent the secrets from living in memory after they are used so they won't be leaked,
92+
* for that we zero out the buffer.
93+
*
94+
* TODO: Prevent these writes from being optimized out, as any good compiler will remove any writes that aren't used. */
95+
memset(seckey1, 0, sizeof(seckey1));
96+
memset(seckey2, 0, sizeof(seckey2));
97+
memset(shared_secret1, 0, sizeof(shared_secret1));
98+
memset(shared_secret2, 0, sizeof(shared_secret2));
99+
100+
return 0;
101+
}

0 commit comments

Comments
 (0)