Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1/*************************************************************************2* Written in 2020-2022 by Elichai Turkel *3* To the extent possible under law, the author(s) have dedicated all *4* copyright and related and neighboring rights to the software in this *5* file to the public domain worldwide. This software is distributed *6* without any warranty. For the CC0 Public Domain Dedication, see *7* EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *8*************************************************************************/10#include <stdio.h>11#include <stdlib.h>12#include <assert.h>13#include <string.h>15#include <secp256k1.h>17#include "examples_util.h"19int main(void) {20/* Instead of signing the message directly, we must sign a 32-byte hash.21* Here the message is "Hello, world!" and the hash function was SHA-256.22* An actual implementation should just call SHA-256, but this example23* hardcodes the output to avoid depending on an additional library.24* See https://bitcoin.stackexchange.com/questions/81115/if-someone-wanted-to-pretend-to-be-satoshi-by-posting-a-fake-signature-to-defrau/81116#81116 */25unsigned char msg_hash[32] = {260x31, 0x5F, 0x5B, 0xDB, 0x76, 0xD0, 0x78, 0xC4,270x3B, 0x8A, 0xC0, 0x06, 0x4E, 0x4A, 0x01, 0x64,280x61, 0x2B, 0x1F, 0xCE, 0x77, 0xC8, 0x69, 0x34,290x5B, 0xFC, 0x94, 0xC7, 0x58, 0x94, 0xED, 0xD3,30};31unsigned char seckey[32];32unsigned char randomize[32];33unsigned char compressed_pubkey[33];34unsigned char serialized_signature[64];35size_t len;36int is_signature_valid, is_signature_valid2;37int return_val;38secp256k1_pubkey pubkey;39secp256k1_ecdsa_signature sig;40/* Before we can call actual API functions, we need to create a "context". */41secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);42if (!fill_random(randomize, sizeof(randomize))) {43printf("Failed to generate randomness\n");44return EXIT_FAILURE;45}46/* Randomizing the context is recommended to protect against side-channel47* leakage See `secp256k1_context_randomize` in secp256k1.h for more48* information about it. This should never fail. */49return_val = secp256k1_context_randomize(ctx, randomize);50assert(return_val);52/*** Key Generation ***/53if (!fill_random(seckey, sizeof(seckey))) {54printf("Failed to generate randomness\n");55return EXIT_FAILURE;56}57/* If the secret key is zero or out of range (greater than secp256k1's58* order), we fail. Note that the probability of this occurring is negligible59* with a properly functioning random number generator. */60if (!secp256k1_ec_seckey_verify(ctx, seckey)) {61printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n");62return EXIT_FAILURE;63}65/* Public key creation using a valid context with a verified secret key should never fail */66return_val = secp256k1_ec_pubkey_create(ctx, &pubkey, seckey);67assert(return_val);69/* Serialize the pubkey in a compressed form(33 bytes). Should always return 1. */70len = sizeof(compressed_pubkey);71return_val = secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey, &len, &pubkey, SECP256K1_EC_COMPRESSED);72assert(return_val);73/* Should be the same size as the size of the output, because we passed a 33 byte array. */74assert(len == sizeof(compressed_pubkey));76/*** Signing ***/78/* Generate an ECDSA signature `noncefp` and `ndata` allows you to pass a79* custom nonce function, passing `NULL` will use the RFC-6979 safe default.80* Signing with a valid context, verified secret key81* and the default nonce function should never fail. */82return_val = secp256k1_ecdsa_sign(ctx, &sig, msg_hash, seckey, NULL, NULL);83assert(return_val);85/* Serialize the signature in a compact form. Should always return 186* according to the documentation in secp256k1.h. */87return_val = secp256k1_ecdsa_signature_serialize_compact(ctx, serialized_signature, &sig);88assert(return_val);91/*** Verification ***/93/* Deserialize the signature. This will return 0 if the signature can't be parsed correctly. */94if (!secp256k1_ecdsa_signature_parse_compact(ctx, &sig, serialized_signature)) {95printf("Failed parsing the signature\n");96return EXIT_FAILURE;97}99/* Deserialize the public key. This will return 0 if the public key can't be parsed correctly. */100if (!secp256k1_ec_pubkey_parse(ctx, &pubkey, compressed_pubkey, sizeof(compressed_pubkey))) {101printf("Failed parsing the public key\n");102return EXIT_FAILURE;103}105/* Verify a signature. This will return 1 if it's valid and 0 if it's not. */106is_signature_valid = secp256k1_ecdsa_verify(ctx, &sig, msg_hash, &pubkey);108printf("Is the signature valid? %s\n", is_signature_valid ? "true" : "false");109printf("Secret Key: ");110print_hex(seckey, sizeof(seckey));111printf("Public Key: ");112print_hex(compressed_pubkey, sizeof(compressed_pubkey));113printf("Signature: ");114print_hex(serialized_signature, sizeof(serialized_signature));116/* This will clear everything from the context and free the memory */117secp256k1_context_destroy(ctx);119/* Bonus example: if all we need is signature verification (and no key120generation or signing), we don't need to use a context created via121secp256k1_context_create(). We can simply use the static (i.e., global)122context secp256k1_context_static. See its description in123include/secp256k1.h for details. */124is_signature_valid2 = secp256k1_ecdsa_verify(secp256k1_context_static,125&sig, msg_hash, &pubkey);126assert(is_signature_valid2 == is_signature_valid);128/* It's best practice to try to clear secrets from memory after using them.129* This is done because some bugs can allow an attacker to leak memory, for130* example through "out of bounds" array access (see Heartbleed), or the OS131* swapping them to disk. Hence, we overwrite the secret key buffer with zeros.132*133* Here we are preventing these writes from being optimized out, as any good compiler134* will remove any writes that aren't used. */135secure_erase(seckey, sizeof(seckey));137return EXIT_SUCCESS;138}
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.