Skip to content

Commit c0c32a6

Browse files
elichaijonasnick
andcommitted
Add a ecdh shared secret example
Co-authored-by: Jonas Nick <jonasd.nick@gmail.com>
1 parent d22500a commit c0c32a6

File tree

1 file changed

+113
-0
lines changed

1 file changed

+113
-0
lines changed

examples/ecdh.c

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
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+
#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+
int main(void) {
17+
unsigned char seckey1[32];
18+
unsigned char seckey2[32];
19+
unsigned char compressed_pubkey1[33];
20+
unsigned char compressed_pubkey2[33];
21+
unsigned char shared_secret1[32];
22+
unsigned char shared_secret2[32];
23+
unsigned char randomize[32];
24+
size_t len;
25+
secp256k1_pubkey pubkey1;
26+
secp256k1_pubkey pubkey2;
27+
28+
/* The docs in secp256k1.h above the `secp256k1_ec_pubkey_create` function
29+
* say: "pointer to a context object, initialized for signing" which is why
30+
* we create a context for signing with the SECP256K1_CONTEXT_SIGN flag.
31+
* (The docs for `secp256k1_ecdh` don't require any special context, just
32+
* some initialized context) */
33+
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
34+
if (!fill_random(randomize, sizeof(randomize))) {
35+
printf("Failed to generate randomness\n");
36+
return 1;
37+
}
38+
/* Randomizing the context is recommended to protect against side-channel
39+
* leakage See `secp256k1_context_randomize` in secp256k1.h for more
40+
* information about it. This should never fail. */
41+
assert(secp256k1_context_randomize(ctx, randomize));
42+
43+
/*** Key Generation ***/
44+
45+
/* If the secret key is zero or out of range (bigger than secp256k1's
46+
* order), we try to sample a new key. Note that the probability of this
47+
* happening is negligible. */
48+
while (1) {
49+
if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) {
50+
printf("Failed to generate randomness\n");
51+
return 1;
52+
}
53+
if (secp256k1_ec_seckey_verify(ctx, seckey1) && secp256k1_ec_seckey_verify(ctx, seckey2)) {
54+
break;
55+
}
56+
}
57+
58+
/* Public key creation using a valid context with a verified secret key should never fail */
59+
assert(secp256k1_ec_pubkey_create(ctx, &pubkey1, seckey1));
60+
assert(secp256k1_ec_pubkey_create(ctx, &pubkey2, seckey2));
61+
62+
/* Serialize pubkey1 in a compressed form (33 bytes), should always return 1 */
63+
len = sizeof(compressed_pubkey1);
64+
assert(secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey1, &len, &pubkey1, SECP256K1_EC_COMPRESSED));
65+
/* Should be the same size as the size of the output, because we passed a 33 bytes array. */
66+
assert(len == sizeof(compressed_pubkey1));
67+
68+
/* Serialize pubkey2 in a compressed form (33 bytes) */
69+
len = sizeof(compressed_pubkey2);
70+
secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey2, &len, &pubkey2, SECP256K1_EC_COMPRESSED);
71+
assert(len == sizeof(compressed_pubkey2));
72+
73+
/*** Creating the shared secret ***/
74+
75+
/* Perform ECDH with seckey1 and pubkey2. Should never fail with a verified
76+
* seckey and valid pubkey */
77+
assert(secp256k1_ecdh(ctx, shared_secret1, &pubkey2, seckey1, NULL, NULL));
78+
79+
/* Perform ECDH with seckey2 and pubkey1. Should never fail with a verified
80+
* seckey and valid pubkey */
81+
assert(secp256k1_ecdh(ctx, shared_secret2, &pubkey1, seckey2, NULL, NULL));
82+
83+
/* Both parties should end up with the same shared secret */
84+
assert(memcmp(shared_secret1, shared_secret2, sizeof(shared_secret1)) == 0);
85+
86+
printf("Secret Key1: ");
87+
print_hex(seckey1, sizeof(seckey1));
88+
printf("Compressed Pubkey1: ");
89+
print_hex(compressed_pubkey1, sizeof(compressed_pubkey1));
90+
printf("\nSecret Key2: ");
91+
print_hex(seckey2, sizeof(seckey2));
92+
printf("Compressed Pubkey2: ");
93+
print_hex(compressed_pubkey2, sizeof(compressed_pubkey2));
94+
printf("\nShared Secret: ");
95+
print_hex(shared_secret1, sizeof(shared_secret1));
96+
97+
/* This will clear everything from the context and free the memory */
98+
secp256k1_context_destroy(ctx);
99+
100+
/* It's best practice to try to remove secrets from memory after using them.
101+
* This is done because some bugs can allow an attacker leak memory, for
102+
* example through out of bounds array access (see Heartbleed for example).
103+
* Hence, we overwrite the secret key buffer with zeros.
104+
*
105+
* TODO: Prevent these writes from being optimized out, as any good compiler
106+
* will remove any writes that aren't used. */
107+
memset(seckey1, 0, sizeof(seckey1));
108+
memset(seckey2, 0, sizeof(seckey2));
109+
memset(shared_secret1, 0, sizeof(shared_secret1));
110+
memset(shared_secret2, 0, sizeof(shared_secret2));
111+
112+
return 0;
113+
}

0 commit comments

Comments
 (0)