2020-04-30 13:37:52 +03:00
/*************************************************************************
* Written in 2020-2022 by Elichai Turkel *
* 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 <stdio.h>
2025-02-14 13:43:10 +01:00
#include <stdlib.h>
2020-04-30 13:37:52 +03:00
#include <assert.h>
#include <string.h>
#include <secp256k1.h>
2023-02-17 14:08:06 +05:30
#include "examples_util.h"
2020-04-30 13:37:52 +03:00
int main ( void ) {
/* Instead of signing the message directly, we must sign a 32-byte hash.
* Here the message is "Hello, world!" and the hash function was SHA-256.
* An actual implementation should just call SHA-256, but this example
* hardcodes the output to avoid depending on an additional library.
* See https://bitcoin.stackexchange.com/questions/81115/if-someone-wanted-to-pretend-to-be-satoshi-by-posting-a-fake-signature-to-defrau/81116#81116 */
unsigned char msg_hash [ 32 ] = {
0x31 , 0x5F , 0x5B , 0xDB , 0x76 , 0xD0 , 0x78 , 0xC4 ,
0x3B , 0x8A , 0xC0 , 0x06 , 0x4E , 0x4A , 0x01 , 0x64 ,
0x61 , 0x2B , 0x1F , 0xCE , 0x77 , 0xC8 , 0x69 , 0x34 ,
0x5B , 0xFC , 0x94 , 0xC7 , 0x58 , 0x94 , 0xED , 0xD3 ,
};
unsigned char seckey [ 32 ];
unsigned char randomize [ 32 ];
unsigned char compressed_pubkey [ 33 ];
unsigned char serialized_signature [ 64 ];
size_t len ;
2023-02-06 21:31:47 +01:00
int is_signature_valid , is_signature_valid2 ;
2020-04-30 13:37:52 +03:00
int return_val ;
secp256k1_pubkey pubkey ;
secp256k1_ecdsa_signature sig ;
2022-11-25 22:32:11 +01:00
/* Before we can call actual API functions, we need to create a "context". */
secp256k1_context * ctx = secp256k1_context_create ( SECP256K1_CONTEXT_NONE );
2020-04-30 13:37:52 +03:00
if ( ! fill_random ( randomize , sizeof ( randomize ))) {
printf ( "Failed to generate randomness \n " );
2025-02-14 13:43:10 +01:00
return EXIT_FAILURE ;
2020-04-30 13:37:52 +03:00
}
/* 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 );
/*** Key Generation ***/
2024-08-29 22:24:20 +02:00
if ( ! fill_random ( seckey , sizeof ( seckey ))) {
printf ( "Failed to generate randomness \n " );
2025-02-14 13:43:10 +01:00
return EXIT_FAILURE ;
2024-08-29 22:24:20 +02:00
}
2024-10-13 19:11:02 +00:00
/* If the secret key is zero or out of range (greater than secp256k1's
* order), we fail. Note that the probability of this occurring is negligible
* with a properly functioning random number generator. */
2024-08-29 22:24:20 +02:00
if ( ! secp256k1_ec_seckey_verify ( ctx , seckey )) {
printf ( "Generated secret key is invalid. This indicates an issue with the random number generator. \n " );
2025-02-14 13:43:10 +01:00
return EXIT_FAILURE ;
2020-04-30 13:37:52 +03:00
}
/* Public key creation using a valid context with a verified secret key should never fail */
return_val = secp256k1_ec_pubkey_create ( ctx , & pubkey , seckey );
assert ( return_val );
/* Serialize the pubkey in a compressed form(33 bytes). Should always return 1. */
len = sizeof ( compressed_pubkey );
return_val = secp256k1_ec_pubkey_serialize ( ctx , compressed_pubkey , & len , & pubkey , SECP256K1_EC_COMPRESSED );
assert ( return_val );
/* Should be the same size as the size of the output, because we passed a 33 byte array. */
assert ( len == sizeof ( compressed_pubkey ));
/*** Signing ***/
/* Generate an ECDSA signature `noncefp` and `ndata` allows you to pass a
* custom nonce function, passing `NULL` will use the RFC-6979 safe default.
* Signing with a valid context, verified secret key
* and the default nonce function should never fail. */
return_val = secp256k1_ecdsa_sign ( ctx , & sig , msg_hash , seckey , NULL , NULL );
assert ( return_val );
/* Serialize the signature in a compact form. Should always return 1
* according to the documentation in secp256k1.h. */
return_val = secp256k1_ecdsa_signature_serialize_compact ( ctx , serialized_signature , & sig );
assert ( return_val );
/*** Verification ***/
/* Deserialize the signature. This will return 0 if the signature can't be parsed correctly. */
if ( ! secp256k1_ecdsa_signature_parse_compact ( ctx , & sig , serialized_signature )) {
printf ( "Failed parsing the signature \n " );
2025-02-14 13:43:10 +01:00
return EXIT_FAILURE ;
2020-04-30 13:37:52 +03:00
}
/* Deserialize the public key. This will return 0 if the public key can't be parsed correctly. */
if ( ! secp256k1_ec_pubkey_parse ( ctx , & pubkey , compressed_pubkey , sizeof ( compressed_pubkey ))) {
printf ( "Failed parsing the public key \n " );
2025-02-14 13:43:10 +01:00
return EXIT_FAILURE ;
2020-04-30 13:37:52 +03:00
}
/* Verify a signature. This will return 1 if it's valid and 0 if it's not. */
is_signature_valid = secp256k1_ecdsa_verify ( ctx , & sig , msg_hash , & pubkey );
printf ( "Is the signature valid? %s \n " , is_signature_valid ? "true" : "false" );
printf ( "Secret Key: " );
print_hex ( seckey , sizeof ( seckey ));
printf ( "Public Key: " );
print_hex ( compressed_pubkey , sizeof ( compressed_pubkey ));
printf ( "Signature: " );
print_hex ( serialized_signature , sizeof ( serialized_signature ));
/* This will clear everything from the context and free the memory */
secp256k1_context_destroy ( ctx );
2023-02-06 21:31:47 +01:00
/* Bonus example: if all we need is signature verification (and no key
generation or signing), we don't need to use a context created via
secp256k1_context_create(). We can simply use the static (i.e., global)
context secp256k1_context_static. See its description in
include/secp256k1.h for details. */
is_signature_valid2 = secp256k1_ecdsa_verify ( secp256k1_context_static ,
& sig , msg_hash , & pubkey );
assert ( is_signature_valid2 == is_signature_valid );
2020-04-30 13:37:52 +03:00
/* 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
2024-06-25 16:52:38 +02:00
* example through "out of bounds" array access (see Heartbleed), or the OS
2020-04-30 13:37:52 +03:00
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
*
2023-02-17 14:08:06 +05:30
* Here we are preventing these writes from being optimized out, as any good compiler
2020-04-30 13:37:52 +03:00
* will remove any writes that aren't used. */
2023-02-17 14:08:06 +05:30
secure_erase ( seckey , sizeof ( seckey ));
2020-04-30 13:37:52 +03:00
2025-02-14 13:43:10 +01:00
return EXIT_SUCCESS ;
2020-04-30 13:37:52 +03:00
}