1818#include "random.h"
1919
2020int main (void ) {
21- /* Instead of signing the message directly, we must sign a 32-byte hash.
22- * Here the message is "Hello, world!" and the hash function was SHA-256.
23- * An actual implementation should just call SHA-256, but this example
24- * hardcodes the output to avoid depending on an additional library. */
25- unsigned char msg_hash [32 ] = {
26- 0x31 , 0x5F , 0x5B , 0xDB , 0x76 , 0xD0 , 0x78 , 0xC4 ,
27- 0x3B , 0x8A , 0xC0 , 0x06 , 0x4E , 0x4A , 0x01 , 0x64 ,
28- 0x61 , 0x2B , 0x1F , 0xCE , 0x77 , 0xC8 , 0x69 , 0x34 ,
29- 0x5B , 0xFC , 0x94 , 0xC7 , 0x58 , 0x94 , 0xED , 0xD3 ,
30- };
21+ unsigned char msg [12 ] = "Hello World!" ;
22+ unsigned char msg_hash [32 ];
23+ unsigned char tag [17 ] = "my_fancy_protocol" ;
3124 unsigned char seckey [32 ];
3225 unsigned char randomize [32 ];
3326 unsigned char auxiliary_rand [32 ];
@@ -84,18 +77,37 @@ int main(void) {
8477
8578 /*** Signing ***/
8679
80+ /* Instead of signing (possibly very long) messages directly, we sign a
81+ * 32-byte hash of the message in this example.
82+ *
83+ * We use secp256k1_tagged_sha256 to create this hash. This function expects
84+ * a context-specific "tag", which restricts the context in which the signed
85+ * messages should be considered valid. For example, if protocol A mandates
86+ * to use the tag "my_fancy_protocol" and protocol B mandates to use the tag
87+ * "my_boring_protocol", then signed messages from protocol A will never be
88+ * valid in protocol B (and vice versa), even if keys are reused across
89+ * protocols. This implements "domain separation", which is considered good
90+ * practice. It avoids attacks in which users are tricked into signing a
91+ * message that has intended consequences in the intended context (e.g.,
92+ * protocol A) but would have unintended consequences if it were valid in
93+ * some other context (e.g., protocol B). */
94+ return_val = secp256k1_tagged_sha256 (ctx , msg_hash , tag , sizeof (tag ), msg , sizeof (msg ));
95+ assert (return_val );
96+
8797 /* Generate 32 bytes of randomness to use with BIP-340 schnorr signing. */
8898 if (!fill_random (auxiliary_rand , sizeof (auxiliary_rand ))) {
8999 printf ("Failed to generate randomness\n" );
90100 return 1 ;
91101 }
92102
93- /* Generate a Schnorr signature `noncefp` and `ndata` allows you to pass a
94- * custom nonce function, passing `NULL` will use the BIP-340 safe default.
95- * BIP-340 recommends passing 32 bytes of randomness to the nonce function to
96- * improve security against side-channel attacks. Signing with a valid
97- * context, verified keypair and the default nonce function should never
98- * fail. */
103+ /* Generate a Schnorr signature.
104+ *
105+ * We use the secp256k1_schnorrsig_sign32 function that provides a simple
106+ * interface for signing 32-byte messages (which in our case is a hash of
107+ * the actual message). BIP-340 recommends passing 32 bytes of randomness
108+ * to the signing function to improve security against side-channel attacks.
109+ * Signing with a valid context, a 32-byte message, a verified keypair, and
110+ * any 32 bytes of auxiliary random data should never fail. */
99111 return_val = secp256k1_schnorrsig_sign32 (ctx , signature , msg_hash , & keypair , auxiliary_rand );
100112 assert (return_val );
101113
@@ -108,6 +120,10 @@ int main(void) {
108120 return 1 ;
109121 }
110122
123+ /* Compute the tagged hash on the received messages using the same tag as the signer. */
124+ return_val = secp256k1_tagged_sha256 (ctx , msg_hash , tag , sizeof (tag ), msg , sizeof (msg ));
125+ assert (return_val );
126+
111127 /* Verify a signature. This will return 1 if it's valid and 0 if it's not. */
112128 is_signature_valid = secp256k1_schnorrsig_verify (ctx , signature , msg_hash , 32 , & pubkey );
113129
0 commit comments