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