nostril

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

nostril.c (26094B)


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