nostril

A C cli tool for creating nostr events
git clone git://jb55.com/nostril
Log | Files | Refs | Submodules | README | LICENSE

nostril.c (20351B)


      1 
      2 #include <stdio.h>
      3 #include <time.h>
      4 #include <stdlib.h>
      5 #include <assert.h>
      6 #include <errno.h>
      7 #include <inttypes.h>
      8 #include <unistd.h>
      9 
     10 #include "secp256k1.h"
     11 #include "secp256k1_ecdh.h"
     12 #include "secp256k1_schnorrsig.h"
     13 
     14 #include "cursor.h"
     15 #include "hex.h"
     16 #include "base64.h"
     17 #include "aes.h"
     18 #include "sha256.h"
     19 #include "random.h"
     20 #include "proof.h"
     21 
     22 #define VERSION "0.1.3"
     23 
     24 #define MAX_TAGS 32
     25 #define MAX_TAG_ELEMS 16
     26 
     27 #define HAS_CREATED_AT (1<<1)
     28 #define HAS_KIND (1<<2)
     29 #define HAS_ENVELOPE (1<<3)
     30 #define HAS_ENCRYPT (1<<4)
     31 #define HAS_DIFFICULTY (1<<5)
     32 #define HAS_MINE_PUBKEY (1<<6)
     33 
     34 struct key {
     35 	secp256k1_keypair pair;
     36 	unsigned char secret[32];
     37 	unsigned char pubkey[32];
     38 };
     39 
     40 struct args {
     41 	unsigned int flags;
     42 	int kind;
     43 	int difficulty;
     44 
     45 	unsigned char encrypt_to[32];
     46 	const char *sec;
     47 	const char *tags;
     48 	const char *content;
     49 
     50 	uint64_t created_at;
     51 };
     52 
     53 struct nostr_tag {
     54 	const char *strs[MAX_TAG_ELEMS];
     55 	int num_elems;
     56 };
     57 
     58 struct nostr_event {
     59 	unsigned char id[32];
     60 	unsigned char pubkey[32];
     61 	unsigned char sig[64];
     62 
     63 	const char *content;
     64 
     65 	uint64_t created_at;
     66 	int kind;
     67 
     68 	const char *explicit_tags;
     69 
     70 	struct nostr_tag tags[MAX_TAGS];
     71 	int num_tags;
     72 };
     73 
     74 void usage()
     75 {
     76 	printf("usage: nostril [OPTIONS]\n");
     77 	printf("\n");
     78 	printf("  OPTIONS\n");
     79 	printf("\n");
     80 	printf("      --content <string>              the content of the note\n");
     81 	printf("      --dm <hex pubkey>               make an encrypted dm to said pubkey. sets kind and tags.\n");
     82 	printf("      --envelope                      wrap in [\"EVENT\",...] for easy relaying\n");
     83 	printf("      --kind <number>                 set kind\n");
     84 	printf("      --created-at <unix timestamp>   set a specific created-at time\n");
     85 	printf("      --sec <hex seckey>              set the secret key for signing, otherwise one will be randomly generated\n");
     86 	printf("      --pow <difficulty>              number of leading 0 bits of the id to mine\n");
     87 	printf("      --mine-pubkey                   mine a pubkey instead of id\n");
     88 	printf("      --tag <key> <value>             add a tag\n");
     89 	printf("      -e <event_id>                   shorthand for --tag e <event_id>\n");
     90 	printf("      -p <pubkey>                     shorthand for --tag p <pubkey>\n");
     91 	printf("      -t <hashtag>                    shorthand for --tag t <hashtag>\n");
     92 	exit(1);
     93 }
     94 
     95 
     96 inline static int cursor_push_escaped_char(struct cursor *cur, char c)
     97 {
     98         switch (c) {
     99         case '"':  return cursor_push_str(cur, "\\\"");
    100         case '\\': return cursor_push_str(cur, "\\\\");
    101         case '\b': return cursor_push_str(cur, "\\b");
    102         case '\f': return cursor_push_str(cur, "\\f");
    103         case '\n': return cursor_push_str(cur, "\\n");
    104         case '\r': return cursor_push_str(cur, "\\r");
    105         case '\t': return cursor_push_str(cur, "\\t");
    106         // TODO: \u hex hex hex hex
    107         }
    108         return cursor_push_byte(cur, c);
    109 }
    110 
    111 static int cursor_push_jsonstr(struct cursor *cur, const char *str)
    112 {
    113 	int i;
    114         int len;
    115 
    116 	len = strlen(str);
    117 
    118         if (!cursor_push_byte(cur, '"'))
    119                 return 0;
    120 
    121         for (i = 0; i < len; i++) {
    122                 if (!cursor_push_escaped_char(cur, str[i]))
    123                         return 0;
    124         }
    125 
    126         if (!cursor_push_byte(cur, '"'))
    127                 return 0;
    128 
    129         return 1;
    130 }
    131 
    132 static int cursor_push_tag(struct cursor *cur, struct nostr_tag *tag)
    133 {
    134         int i;
    135 
    136         if (!cursor_push_byte(cur, '['))
    137                 return 0;
    138 
    139         for (i = 0; i < tag->num_elems; i++) {
    140                 if (!cursor_push_jsonstr(cur, tag->strs[i]))
    141                         return 0;
    142                 if (i != tag->num_elems-1) {
    143                         if (!cursor_push_byte(cur, ','))
    144                                 return 0;
    145                 }
    146         }
    147 
    148         return cursor_push_byte(cur, ']');
    149 }
    150 
    151 static int cursor_push_tags(struct cursor *cur, struct nostr_event *ev)
    152 {
    153         int i;
    154 
    155 	if (ev->explicit_tags) {
    156 		return cursor_push_str(cur, ev->explicit_tags);
    157 	}
    158 
    159         if (!cursor_push_byte(cur, '['))
    160                 return 0;
    161 
    162         for (i = 0; i < ev->num_tags; i++) {
    163                 if (!cursor_push_tag(cur, &ev->tags[i]))
    164                         return 0;
    165                 if (i != ev->num_tags-1) {
    166                         if (!cursor_push_str(cur, ","))
    167                                 return 0;
    168                 }
    169         }
    170 
    171         return cursor_push_byte(cur, ']');
    172 }
    173 
    174 
    175 int event_commitment(struct nostr_event *ev, unsigned char *buf, int buflen)
    176 {
    177 	char timebuf[16] = {0};
    178 	char kindbuf[16] = {0};
    179 	char pubkey[65];
    180 	struct cursor cur;
    181 	int ok;
    182 
    183 	ok = hex_encode(ev->pubkey, sizeof(ev->pubkey), pubkey, sizeof(pubkey));
    184 	assert(ok);
    185 
    186 	make_cursor(buf, buf + buflen, &cur);
    187 
    188 	snprintf(timebuf, sizeof(timebuf), "%" PRIu64 "", ev->created_at);
    189         snprintf(kindbuf, sizeof(kindbuf), "%d", ev->kind);
    190 
    191 	ok =
    192                 cursor_push_str(&cur, "[0,\"") &&
    193                 cursor_push_str(&cur, pubkey) &&
    194                 cursor_push_str(&cur, "\",") &&
    195                 cursor_push_str(&cur, timebuf) &&
    196                 cursor_push_str(&cur, ",") &&
    197                 cursor_push_str(&cur, kindbuf) &&
    198                 cursor_push_str(&cur, ",") &&
    199                 cursor_push_tags(&cur, ev) &&
    200                 cursor_push_str(&cur, ",") &&
    201                 cursor_push_jsonstr(&cur, ev->content) &&
    202                 cursor_push_str(&cur, "]");
    203 
    204 	if (!ok)
    205 		return 0;
    206 
    207 	return cur.p - cur.start;
    208 }
    209 
    210 static int make_sig(secp256k1_context *ctx, struct key *key,
    211 		unsigned char *id, unsigned char sig[64])
    212 {
    213 	unsigned char aux[32];
    214 
    215 	if (!fill_random(aux, sizeof(aux))) {
    216 		return 0;
    217 	}
    218 
    219 	return secp256k1_schnorrsig_sign32(ctx, sig, id, &key->pair, aux);
    220 }
    221 
    222 static int create_key(secp256k1_context *ctx, struct key *key)
    223 {
    224 	secp256k1_xonly_pubkey pubkey;
    225 
    226 	/* Try to create a keypair with a valid context, it should only
    227 	 * fail if the secret key is zero or out of range. */
    228 	if (!secp256k1_keypair_create(ctx, &key->pair, key->secret))
    229 		return 0;
    230 
    231 	if (!secp256k1_keypair_xonly_pub(ctx, &pubkey, NULL, &key->pair))
    232 		return 0;
    233 
    234 	/* Serialize the public key. Should always return 1 for a valid public key. */
    235 	return secp256k1_xonly_pubkey_serialize(ctx, key->pubkey, &pubkey);
    236 }
    237 
    238 static int decode_key(secp256k1_context *ctx, const char *secstr, struct key *key)
    239 {
    240 	if (!hex_decode(secstr, strlen(secstr), key->secret, 32)) {
    241 		fprintf(stderr, "could not hex decode secret key\n");
    242 		return 0;
    243 	}
    244 
    245 	return create_key(ctx, key);
    246 }
    247 
    248 static inline void xor_mix(unsigned char *dest, const unsigned char *a, const unsigned char *b, int size)
    249 {
    250     int i;
    251     for (i = 0; i < size; i++)
    252         dest[i] = a[i] ^ b[i];
    253 }
    254 
    255 static int generate_key(secp256k1_context *ctx, struct key *key, int *difficulty)
    256 {
    257 	uint64_t attempts = 0;
    258 	uint64_t duration;
    259 	int bits;
    260 	double pers;
    261 	struct timespec t1, t2;
    262 
    263 	/* If the secret key is zero or out of range (bigger than secp256k1's
    264 	 * order), we try to sample a new key. Note that the probability of this
    265 	 * happening is negligible. */
    266 	if (!fill_random(key->secret, sizeof(key->secret))) {
    267 		return 0;
    268 	}
    269 
    270 	if (difficulty == NULL) {
    271 		return create_key(ctx, key);
    272 	}
    273 
    274 	clock_gettime(CLOCK_MONOTONIC, &t1);
    275 	while (1) {
    276 		if (!create_key(ctx, key))
    277 			return 0;
    278 
    279 		attempts++;
    280 
    281 		if ((bits = count_leading_zero_bits(key->pubkey)) >= *difficulty) {
    282 			clock_gettime(CLOCK_MONOTONIC, &t2);
    283 			duration = ((t2.tv_sec - t1.tv_sec) * 1e9L + (t2.tv_nsec - t1.tv_nsec)) / 1e6L;
    284 			pers = (double)attempts / (double)duration;
    285 			fprintf(stderr, "mined pubkey with %d bits after %" PRIu64 " attempts, %" PRId64 " ms, %f attempts per ms\n", bits, attempts, duration, pers);
    286 			return 1;
    287 		}
    288 
    289 		// NOTE: Get a new secret key by xor mixing the current secret
    290 		// key with the current public key. This doesn't rely on the
    291 		// system's crypto number generator so it should be fast. There
    292 		// shouldn't be any secret key entropy issues since we got a
    293 		// good source of entropy from the first fill_random call at
    294 		// the start of the function.
    295 		xor_mix(key->secret, key->secret, key->pubkey, 32);
    296 	}
    297 }
    298 
    299 
    300 static int init_secp_context(secp256k1_context **ctx)
    301 {
    302 	unsigned char randomize[32];
    303 
    304 	*ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
    305 	if (!fill_random(randomize, sizeof(randomize))) {
    306 		return 0;
    307 	}
    308 
    309 	/* Randomizing the context is recommended to protect against side-channel
    310 	 * leakage See `secp256k1_context_randomize` in secp256k1.h for more
    311 	 * information about it. This should never fail. */
    312 	return secp256k1_context_randomize(*ctx, randomize);
    313 }
    314 
    315 static int generate_event_id(struct nostr_event *ev)
    316 {
    317 	static unsigned char buf[102400];
    318 
    319 	int len;
    320 
    321 	if (!(len = event_commitment(ev, buf, sizeof(buf)))) {
    322 		fprintf(stderr, "event_commitment: buffer out of space\n");
    323 		return 0;
    324 	}
    325 
    326 	//fprintf(stderr, "commitment: '%.*s'\n", len, buf);
    327 
    328 	sha256((struct sha256*)ev->id, buf, len);
    329 
    330 	return 1;
    331 }
    332 
    333 static int sign_event(secp256k1_context *ctx, struct key *key, struct nostr_event *ev)
    334 {
    335 	if (!make_sig(ctx, key, ev->id, ev->sig))
    336 		return 0;
    337 
    338 	return 1;
    339 }
    340 
    341 static int print_event(struct nostr_event *ev, int envelope)
    342 {
    343 	unsigned char buf[102400];
    344 	char pubkey[65];
    345 	char id[65];
    346 	char sig[129];
    347 	struct cursor cur;
    348 	int ok;
    349 
    350 	ok = hex_encode(ev->id, sizeof(ev->id), id, sizeof(id)) &&
    351 	hex_encode(ev->pubkey, sizeof(ev->pubkey), pubkey, sizeof(pubkey)) &&
    352 	hex_encode(ev->sig, sizeof(ev->sig), sig, sizeof(sig));
    353 
    354 	assert(ok);
    355 
    356 	make_cursor(buf, buf+sizeof(buf), &cur);
    357 	if (!cursor_push_tags(&cur, ev))
    358 		return 0;
    359 
    360 	if (envelope)
    361 		printf("[\"EVENT\",");
    362 
    363 	printf("{\"id\": \"%s\",", id);
    364 	printf("\"pubkey\": \"%s\",", pubkey);
    365 	printf("\"created_at\": %" PRIu64 ",", ev->created_at);
    366 	printf("\"kind\": %d,", ev->kind);
    367 	printf("\"tags\": %.*s,", (int)cursor_len(&cur), cur.start);
    368 
    369 	reset_cursor(&cur);
    370 	if (!cursor_push_jsonstr(&cur, ev->content))
    371 		return 0;
    372 
    373 	printf("\"content\": %.*s,", (int)cursor_len(&cur), cur.start);
    374 	printf("\"sig\": \"%s\"}", sig);
    375 
    376 	if (envelope)
    377 		printf("]");
    378 
    379 	printf("\n");
    380 
    381 	return 1;
    382 }
    383 
    384 static void make_event_from_args(struct nostr_event *ev, struct args *args)
    385 {
    386 	ev->created_at = args->flags & HAS_CREATED_AT? args->created_at : time(NULL);
    387 	ev->content = args->content;
    388 	ev->kind = args->flags & HAS_KIND ? args->kind : 1;
    389 }
    390 
    391 static int parse_num(const char *arg, uint64_t *t)
    392 {
    393 	*t = strtol(arg, NULL, 10);
    394 	return errno != EINVAL;
    395 }
    396 
    397 static int nostr_add_tag_n(struct nostr_event *ev, const char **ts, int n_ts)
    398 {
    399 	int i;
    400 	struct nostr_tag *tag;
    401 
    402 	if (ev->num_tags + 1 > MAX_TAGS)
    403 		return 0;
    404 
    405 	tag = &ev->tags[ev->num_tags++];
    406 
    407 	tag->num_elems = n_ts;
    408 	for (i = 0; i < n_ts; i++) {
    409 		tag->strs[i] = ts[i];
    410 	}
    411 
    412 	return 1;
    413 }
    414 
    415 static int nostr_add_tag(struct nostr_event *ev, const char *t1, const char *t2)
    416 {
    417 	const char *ts[] = {t1, t2};
    418 	return nostr_add_tag_n(ev, ts, 2);
    419 }
    420 
    421 
    422 static int parse_args(int argc, const char *argv[], struct args *args, struct nostr_event *ev)
    423 {
    424 	const char *arg, *arg2;
    425 	uint64_t n;
    426 	int has_added_tags = 0;
    427 
    428 	argv++; argc--;
    429 	for (; argc; ) {
    430 		arg = *argv++; argc--;
    431 
    432 		if (!strcmp(arg, "--help")) {
    433 			usage();
    434 		}
    435 
    436 		if (!argc) {
    437 			fprintf(stderr, "expected argument: '%s'\n", arg);
    438 			return 0;
    439 		}
    440 
    441 		if (!strcmp(arg, "--sec")) {
    442 			args->sec = *argv++; argc--;
    443 		} else if (!strcmp(arg, "--created-at")) {
    444 			arg = *argv++; argc--;
    445 			if (!parse_num(arg, &args->created_at)) {
    446 				fprintf(stderr, "created-at must be a unix timestamp\n");
    447 				return 0;
    448 			} else {
    449 				args->flags |= HAS_CREATED_AT;
    450 			}
    451 		} else if (!strcmp(arg, "--kind")) {
    452 			arg = *argv++; argc--;
    453 			if (!parse_num(arg, &n)) {
    454 				fprintf(stderr, "kind should be a number, got '%s'\n", arg);
    455 				return 0;
    456 			}
    457 			args->kind = (int)n;
    458 			args->flags |= HAS_KIND;
    459 		} else if (!strcmp(arg, "--envelope")) {
    460 			args->flags |= HAS_ENVELOPE;
    461 		} else if (!strcmp(arg, "--tags")) {
    462 			if (args->flags & HAS_DIFFICULTY) {
    463 				fprintf(stderr, "can't combine --tags and --pow (yet)\n");
    464 				return 0;
    465 			}
    466 			if (has_added_tags) {
    467 				fprintf(stderr, "can't combine --tags and --tag (yet)");
    468 				return 0;
    469 			}
    470 			arg = *argv++; argc--;
    471 			args->tags = arg;
    472 		} else if (!strcmp(arg, "-e")) {
    473 			has_added_tags = 1;
    474 			arg = *argv++; argc--;
    475 			if (!nostr_add_tag(ev, "e", arg)) {
    476 				fprintf(stderr, "couldn't add e tag");
    477 				return 0;
    478 			}
    479 		} else if (!strcmp(arg, "-p")) {
    480 			has_added_tags = 1;
    481 			arg = *argv++; argc--;
    482 			if (!nostr_add_tag(ev, "p", arg)) {
    483 				fprintf(stderr, "couldn't add p tag");
    484 				return 0;
    485 			}
    486 		} else if (!strcmp(arg, "-t")) {
    487 			has_added_tags = 1;
    488 			arg = *argv++; argc--;
    489 			if (!nostr_add_tag(ev, "t", arg)) {
    490 				fprintf(stderr, "couldn't add t tag");
    491 				return 0;
    492 			}
    493 		} else if (!strcmp(arg, "--tag")) {
    494 			has_added_tags = 1;
    495 			if (args->tags) {
    496 				fprintf(stderr, "can't combine --tag and --tags (yet)");
    497 				return 0;
    498 			}
    499 			arg = *argv++; argc--;
    500 			if (argc == 0) {
    501 				fprintf(stderr, "expected two arguments to --tag\n");
    502 				return 0;
    503 			}
    504 			arg2 = *argv++; argc--;
    505 			if (!nostr_add_tag(ev, arg, arg2)) {
    506 				fprintf(stderr, "couldn't add tag '%s' '%s'\n", arg, arg2);
    507 				return 0;
    508 			}
    509 		} else if (!strcmp(arg, "--mine-pubkey")) {
    510 			args->flags |= HAS_MINE_PUBKEY;
    511 		} else if (!strcmp(arg, "--pow")) {
    512 			if (args->tags) {
    513 				fprintf(stderr, "can't combine --tags and --pow (yet)\n");
    514 				return 0;
    515 			}
    516 			arg = *argv++; argc--;
    517 			if (!parse_num(arg, &n)) {
    518 				fprintf(stderr, "could not parse difficulty as number: '%s'\n", arg);
    519 				return 0;
    520 			}
    521 			args->difficulty = n;
    522 			args->flags |= HAS_DIFFICULTY;
    523 		} else if (!strcmp(arg, "--dm")) {
    524 			arg = *argv++; argc--;
    525 			if (!hex_decode(arg, strlen(arg), args->encrypt_to, 32)) {
    526 				fprintf(stderr, "could not decode encrypt-to pubkey");
    527 				return 0;
    528 			}
    529 			args->flags |= HAS_ENCRYPT;
    530 		} else if (!strcmp(arg, "--content")) {
    531 			arg = *argv++; argc--;
    532 			args->content = arg;
    533 		} else {
    534 			fprintf(stderr, "unexpected argument '%s'\n", arg);
    535 			return 0;
    536 		}
    537 	}
    538 
    539 	if (!args->content)
    540 		args->content = "";
    541 
    542 	return 1;
    543 }
    544 
    545 static int aes_encrypt(unsigned char *key, unsigned char *iv,
    546 		unsigned char *buf, size_t buflen)
    547 {
    548 	struct AES_ctx ctx;
    549 	unsigned char padding;
    550 	int i;
    551 	struct cursor cur;
    552 
    553 	padding = 16 - (buflen % 16);
    554 	make_cursor(buf, buf + buflen + padding, &cur);
    555 	cur.p += buflen;
    556 	//fprintf(stderr, "aes_encrypt: len %ld, padding %d\n", buflen, padding);
    557 
    558 	for (i = 0; i < padding; i++) {
    559 		if (!cursor_push_byte(&cur, padding)) {
    560 			return 0;
    561 		}
    562 	}
    563 	assert(cur.p == cur.end);
    564 	assert((cur.p - cur.start) % 16 == 0);
    565 
    566 	AES_init_ctx_iv(&ctx, key, iv);
    567 	//fprintf(stderr, "encrypting %ld bytes: ", cur.p - cur.start);
    568 	//print_hex(cur.start, cur.p - cur.start);
    569 	AES_CBC_encrypt_buffer(&ctx, cur.start, cur.p - cur.start);
    570 
    571 	return cur.p - cur.start;
    572 }
    573 
    574 static int copyx(unsigned char *output, const unsigned char *x32, const unsigned char *y32, void *data) {
    575 	memcpy(output, x32, 32);
    576 	return 1;
    577 }
    578 
    579 static int ensure_nonce_tag(struct nostr_event *ev, int target, int *index)
    580 {
    581 	char *str_target = malloc(8);
    582 	struct nostr_tag *tag;
    583 	int i;
    584 
    585 	for (i = 0; i < ev->num_tags; i++) {
    586 		tag = &ev->tags[i];
    587 		if (tag->num_elems == 2 && !strcmp(tag->strs[0], "nonce")) {
    588 			*index = i;
    589 			return 1;
    590 		}
    591 	}
    592 
    593 	*index = ev->num_tags;
    594 
    595 	snprintf(str_target, 7, "%d", target);
    596 	const char *ts[] = { "nonce", "0", str_target };
    597 
    598 	return nostr_add_tag_n(ev, ts, 3);
    599 }
    600 
    601 static int mine_event(struct nostr_event *ev, int difficulty)
    602 {
    603 	char *strnonce = malloc(33);
    604 	struct nostr_tag *tag;
    605 	uint64_t nonce;
    606 	int index, res;
    607 
    608 	if (!ensure_nonce_tag(ev, difficulty, &index))
    609 		return 0;
    610 
    611 	tag = &ev->tags[index];
    612 	assert(tag->num_elems == 3);
    613 	assert(!strcmp(tag->strs[0], "nonce"));
    614 	tag->strs[1] = strnonce;
    615 
    616 	for (nonce = 0;; nonce++) {
    617 		snprintf(strnonce, 32, "%" PRIu64, nonce);
    618 
    619 		if (!generate_event_id(ev))
    620 			return 0;
    621 
    622 		if ((res = count_leading_zero_bits(ev->id)) >= difficulty) {
    623 			fprintf(stderr, "mined %d bits\n", res);
    624 			return 1;
    625 		}
    626 	}
    627 
    628 	return 0;
    629 }
    630 
    631 static int make_encrypted_dm(secp256k1_context *ctx, struct key *key,
    632 		struct nostr_event *ev, unsigned char nostr_pubkey[32], int kind)
    633 {
    634 	size_t inl = strlen(ev->content);
    635 	int enclen = inl + 16;
    636 	size_t buflen = enclen * 3 + 65 * 10;
    637 	unsigned char *buf = malloc(buflen);
    638 	unsigned char shared_secret[32];
    639 	unsigned char iv[16];
    640 	unsigned char compressed_pubkey[33];
    641 	int content_len = strlen(ev->content);
    642 	unsigned char encbuf[content_len + (content_len % 16) + 1];
    643 	struct cursor cur;
    644 	secp256k1_pubkey pubkey;
    645 
    646 	compressed_pubkey[0] = 2;
    647 	memcpy(&compressed_pubkey[1], nostr_pubkey, 32);
    648 
    649 	make_cursor(buf, buf + buflen, &cur);
    650 
    651         if (!secp256k1_ec_seckey_verify(ctx, key->secret)) {
    652 		fprintf(stderr, "make_encrypted_dm: ec_seckey_verify failed\n");
    653 		return 0;
    654 	}
    655 
    656 	if (!secp256k1_ec_pubkey_parse(ctx, &pubkey, compressed_pubkey, sizeof(compressed_pubkey))) {
    657 		fprintf(stderr, "make_encrypted_dm: ec_pubkey_parse failed\n");
    658 		return 0;
    659 	}
    660 
    661 	if (!secp256k1_ecdh(ctx, shared_secret, &pubkey, key->secret, copyx, NULL)) {
    662 		fprintf(stderr, "make_encrypted_dm: secp256k1_ecdh failed\n");
    663 		return 0;
    664 	}
    665 
    666 	if (!fill_random(iv, sizeof(iv))) {
    667 		fprintf(stderr, "make_encrypted_dm: fill_random failed\n");
    668 		return 0;
    669 	}
    670 
    671 	fprintf(stderr, "shared_secret ");
    672 	print_hex(shared_secret, 32);
    673 
    674 	memcpy(encbuf, ev->content, strlen(ev->content));
    675 	enclen = aes_encrypt(shared_secret, iv, encbuf, strlen(ev->content));
    676 	if (enclen == 0) {
    677 		fprintf(stderr, "make_encrypted_dm: aes_encrypt failed\n");
    678 		free(buf);
    679 		return 0;
    680 	}
    681 
    682 	if ((enclen = base64_encode((char *)buf, buflen, (const char*)encbuf, enclen)) == -1) {
    683 		fprintf(stderr, "make_encrypted_dm: base64 encode of encrypted fata failed\n");
    684 		return 0;
    685 	}
    686 	cur.p += enclen;
    687 
    688 	if (!cursor_push_str(&cur, "?iv=")) {
    689 		fprintf(stderr, "make_encrypted_dm: buffer too small\n");
    690 		return 0;
    691 	}
    692 
    693 	if ((enclen = base64_encode((char *)cur.p, cur.end - cur.p, (const char*)iv, 16)) == -1) {
    694 		fprintf(stderr, "make_encrypted_dm: base64 encode of iv failed\n");
    695 		return 0;
    696 	}
    697 	cur.p += enclen;
    698 
    699 	if (!cursor_push_byte(&cur, 0)) {
    700 		fprintf(stderr, "make_encrypted_dm: out of memory by 1 byte!\n");
    701 		return 0;
    702 	}
    703 
    704 	ev->content = (const char*)cur.start;
    705 	ev->kind = kind;
    706 
    707 	if (!hex_encode(nostr_pubkey, 32, (char*)cur.p, cur.end - cur.p))
    708 		return 0;
    709 
    710 	if (!nostr_add_tag(ev, "p", (const char*)cur.p)) {
    711 		fprintf(stderr, "too many tags\n");
    712 		return 0;
    713 	}
    714 
    715 	cur.p += 65;
    716 
    717 	return 1;
    718 }
    719 
    720 static void try_subcommand(int argc, const char *argv[])
    721 {
    722 	static char buf[128] = {0};
    723 	const char *sub = argv[1];
    724 	if (strlen(sub) >= 1 && sub[0] != '-') {
    725 		snprintf(buf, sizeof(buf)-1, "nostril-%s", sub);
    726 		execvp(buf, (char * const *)argv+1);
    727 	}
    728 }
    729 
    730 
    731 int main(int argc, const char *argv[])
    732 {
    733 	struct args args = {0};
    734 	struct nostr_event ev = {0};
    735 	struct key key;
    736         secp256k1_context *ctx;
    737 
    738 	if (argc < 2)
    739 		usage();
    740 
    741         if (!init_secp_context(&ctx))
    742 		return 2;
    743 
    744 	try_subcommand(argc, argv);
    745 
    746 	if (!parse_args(argc, argv, &args, &ev)) {
    747 		usage();
    748 		return 10;
    749 	}
    750 
    751 	if (args.tags) {
    752 		ev.explicit_tags = args.tags;
    753 	}
    754 
    755 	make_event_from_args(&ev, &args);
    756 
    757 	if (args.sec) {
    758 		if (!decode_key(ctx, args.sec, &key)) {
    759 			return 8;
    760 		}
    761 	} else {
    762 		int *difficulty = NULL;
    763 		if ((args.flags & HAS_DIFFICULTY) && (args.flags & HAS_MINE_PUBKEY)) {
    764 			difficulty = &args.difficulty;
    765 		}
    766 
    767 		if (!generate_key(ctx, &key, difficulty)) {
    768 			fprintf(stderr, "could not generate key\n");
    769 			return 4;
    770 		}
    771 		fprintf(stderr, "secret_key ");
    772 		print_hex(key.secret, sizeof(key.secret));
    773 		fprintf(stderr, "\n");
    774 	}
    775 
    776 	if (args.flags & HAS_ENCRYPT) {
    777 		int kind = args.flags & HAS_KIND? args.kind : 4;
    778 		if (!make_encrypted_dm(ctx, &key, &ev, args.encrypt_to, kind)) {
    779 			fprintf(stderr, "error making encrypted dm\n");
    780 			return 0;
    781 		}
    782 	}
    783 
    784 	// set the event's pubkey
    785 	memcpy(ev.pubkey, key.pubkey, 32);
    786 
    787 	if (args.flags & HAS_DIFFICULTY && !(args.flags & HAS_MINE_PUBKEY)) {
    788 		if (!mine_event(&ev, args.difficulty)) {
    789 			fprintf(stderr, "error when mining id\n");
    790 			return 22;
    791 		}
    792 	} else {
    793 		if (!generate_event_id(&ev)) {
    794 			fprintf(stderr, "could not generate event id\n");
    795 			return 5;
    796 		}
    797 	}
    798 
    799 	if (!sign_event(ctx, &key, &ev)) {
    800 		fprintf(stderr, "could not sign event\n");
    801 		return 6;
    802 	}
    803 
    804 	if (!print_event(&ev, args.flags & HAS_ENVELOPE)) {
    805 		fprintf(stderr, "buffer too small\n");
    806 		return 88;
    807 	}
    808 
    809 	return 0;
    810 }
    811