/* For example, in the spec tests we use the following channels: * * lightning/devtools/mkgossip 103x1x0 06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f 0000000000000000000000000000000000000000000000000000000000000002 0000000000000000000000000000000000000000000000000000000000000003 0000000000000000000000000000000000000000000000000000000000000010 0000000000000000000000000000000000000000000000000000000000000020 "" 1565587763 144 0 1000 10 "" "01080808082607" 1565587763 48 0 100 11 100000 "0151b6887026070220014c4e1cc141001e6f65fffec8a825260703c43068ceb641d7b25c3a26070441cf248da2034dfa9351a9e946d71ce86f561f50b67753fd8e385d44647bf62cdb91032607" * * lightning/devtools/mkgossip 109x1x0 06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f 0000000000000000000000000000000000000000000000000000000000000004 0000000000000000000000000000000000000000000000000000000000000005 0000000000000000000000000000000000000000000000000000000000000030 0000000000000000000000000000000000000000000000000000000000000040 "" 1565587764 144 0 1000 10 "" "" 1565587765 48 0 100 11 100000 022a03b0c0000300d000000000240020012607 * * lightning/devtools/mkgossip 115x1x0 06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f 0000000000000000000000000000000000000000000000000000000000000003 0000000000000000000000000000000000000000000000000000000000000004 0000000000000000000000000000000000000000000000000000000000000050 0000000000000000000000000000000000000000000000000000000000000060 "" 1565597764 144 0 1000 10 "" "0441cf248da2034dfa9351a9e946d71ce86f561f50b67753fd8e385d44647bf62cdb91032607" 1565597765 48 0 100 11 100000 "" */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static bool verbose = false; struct update_opts { u32 timestamp; u32 cltv_expiry_delta; struct amount_msat min; struct amount_msat feebase; u32 fee_proportional_millionths; struct amount_msat *max; u8 *addresses; }; static int parse_options(char *argv[], struct update_opts *opts, const char *desc) { int argnum = 0; opts->timestamp = atol(argv[argnum++]); if (!opts->timestamp) errx(1, "Bad %s.timestamp", desc); opts->cltv_expiry_delta = atol(argv[argnum++]); if (!opts->cltv_expiry_delta) errx(1, "Bad %s.cltv_expiry_delta", desc); if (!parse_amount_msat(&opts->min, argv[argnum], strlen(argv[argnum]))) errx(1, "Bad %s.min", desc); argnum++; if (!parse_amount_msat(&opts->feebase, argv[argnum], strlen(argv[argnum]))) errx(1, "Bad %s.feebase", desc); argnum++; opts->fee_proportional_millionths = atol(argv[argnum++]); if (!opts->fee_proportional_millionths) errx(1, "Bad %s.fee_proportional_millionths", desc); if (streq(argv[argnum], "")) opts->max = NULL; else { opts->max = tal(NULL, struct amount_msat); if (!parse_amount_msat(opts->max, argv[argnum], strlen(argv[argnum]))) errx(1, "Bad %s.max", desc); } argnum++; opts->addresses = tal_hexdata(NULL, argv[argnum], strlen(argv[argnum])); if (!opts->addresses) errx(1, "Bad %s.addresses", desc); argnum++; return argnum; } static char *sig_as_hex(const secp256k1_ecdsa_signature *sig) { u8 compact_sig[64]; secp256k1_ecdsa_signature_serialize_compact(secp256k1_ctx, compact_sig, sig); return tal_hexstr(NULL, compact_sig, sizeof(compact_sig)); } static char *sig_notation(const struct privkey *privkey, struct sha256_double *hash, const secp256k1_ecdsa_signature *sig) { const char *pstr = tal_hexstr(NULL, privkey->secret.data, sizeof(privkey->secret.data)); const char *hstr = type_to_string(NULL, struct sha256_double, hash); if (verbose) return tal_fmt(NULL, "SIG(%s:%s)\n" " -- privkey= %s\n" " -- tx_hash= %s\n" " -- computed_sig= %s", pstr, hstr, pstr, hstr, sig_as_hex(sig)); return tal_fmt(NULL, "SIG(%s:%s)", pstr, hstr); } /* BOLT #7: * * The checksum of a `channel_update` is the CRC32C checksum as specified in * [RFC3720](https://tools.ietf.org/html/rfc3720#appendix-B.4) of this * `channel_update` without its `signature` and `timestamp` fields. */ static u32 crc32_of_update(const u8 *channel_update) { u32 sum; /* BOLT #7: * * 1. type: 258 (`channel_update`) * 2. data: * * [`signature`:`signature`] * * [`chain_hash`:`chain_hash`] * * [`short_channel_id`:`short_channel_id`] * * [`u32`:`timestamp`] *... */ /* We already checked it's valid before accepting */ assert(tal_count(channel_update) > 2 + 64 + 32 + 8 + 4); sum = crc32c(0, channel_update + 2 + 64, 32 + 8); sum = crc32c(sum, channel_update + 2 + 64 + 32 + 8 + 4, tal_count(channel_update) - (64 + 2 + 32 + 8 + 4)); return sum; } static void print_update(const struct bitcoin_blkid *chainhash, const struct short_channel_id *scid, const struct update_opts *opts, bool is_lesser_key, const struct privkey *privkey) { /* 2 bytes msg type + 64 bytes of signature */ const size_t channel_update_offset = 2 + 64; struct sha256_double hash; secp256k1_ecdsa_signature sig; u8 *cupdate; memset(&sig, 0, sizeof(sig)); if (opts->max) { cupdate = towire_channel_update_option_channel_htlc_max (NULL, &sig, chainhash, scid, opts->timestamp, ROUTING_OPT_HTLC_MAX_MSAT, is_lesser_key ? 0 : ROUTING_FLAGS_DIRECTION, opts->cltv_expiry_delta, opts->min, opts->feebase.millisatoshis, /* Raw: devtools code */ opts->fee_proportional_millionths, *opts->max); } else { cupdate = towire_channel_update (NULL, &sig, chainhash, scid, opts->timestamp, 0, is_lesser_key ? 0 : ROUTING_FLAGS_DIRECTION, opts->cltv_expiry_delta, opts->min, opts->feebase.millisatoshis, /* Raw: devtools code */ opts->fee_proportional_millionths); } sha256_double(&hash, cupdate + channel_update_offset, tal_count(cupdate) - channel_update_offset); sign_hash(privkey, &hash, &sig); printf("type=channel_update\n"); printf(" signature=%s\n", sig_notation(privkey, &hash, &sig)); printf(" chain_hash=%s\n", tal_hexstr(NULL, chainhash, sizeof(*chainhash))); printf(" short_channel_id=%s\n", short_channel_id_to_str(NULL, scid)); printf(" timestamp=%u\n", opts->timestamp); printf(" message_flags=%u\n", opts->max ? ROUTING_OPT_HTLC_MAX_MSAT : 0); printf(" channel_flags=%u\n", is_lesser_key ? 0 : ROUTING_FLAGS_DIRECTION); printf(" cltv_expiry_delta=%u\n", opts->cltv_expiry_delta); printf(" htlc_minimum_msat=%"PRIu64"\n", opts->min.millisatoshis); /* Raw: devtools code */ printf(" fee_base_msat=%"PRIu64"\n", opts->feebase.millisatoshis); /* Raw: devtools code */ printf(" fee_proportional_millionths=%u\n", opts->fee_proportional_millionths); if (opts->max) printf(" htlc_maximum_msat=%"PRIu64"\n", opts->max->millisatoshis); /* Raw: devtools code */ printf("# crc32c checksum: %08x\n", crc32_of_update(cupdate)); } static void print_nannounce(const struct node_id *nodeid, const struct update_opts *opts, const struct privkey *privkey) { /* 2 bytes msg type + 64 bytes of signature */ const size_t node_announcement_offset = 2 + 64; struct sha256_double hash; secp256k1_ecdsa_signature sig; char alias[33]; u8 *nannounce; memset(&sig, 0, sizeof(sig)); assert(hex_str_size(sizeof(*nodeid)) >= sizeof(alias)); hex_encode(nodeid, hex_data_size(sizeof(alias)), alias, sizeof(alias)); nannounce = towire_node_announcement(NULL, &sig, NULL, opts->timestamp, nodeid, nodeid->k, (u8 *)alias, opts->addresses); sha256_double(&hash, nannounce + node_announcement_offset, tal_count(nannounce) - node_announcement_offset); sign_hash(privkey, &hash, &sig); printf("type=node_announcement\n"); printf(" signature=%s\n", sig_notation(privkey, &hash, &sig)); printf(" features=%s\n", tal_hex(NULL, NULL)); printf(" timestamp=%u\n", opts->timestamp); printf(" node_id=%s\n", node_id_to_hexstr(NULL, nodeid)); printf(" rgb_color=%s\n", tal_hexstr(NULL, nodeid->k, 3)); printf(" alias=%s\n", tal_hexstr(NULL, alias, 32)); printf(" addresses=%s\n", tal_hex(NULL, opts->addresses)); } int main(int argc, char *argv[]) { struct privkey node_privkey[2], funding_privkey[2]; struct pubkey node[2], bitcoin[2]; struct node_id nodeid[2]; int lesser_key; struct short_channel_id scid; struct bitcoin_blkid chainhash; secp256k1_ecdsa_signature nodesig[2], bitcoinsig[2]; const u8 *features; u8 *cannounce; /* 2 bytes msg type + 256 bytes of signatures */ const size_t channel_announcement_offset = 2 + 256; int argnum; struct sha256_double hash; struct update_opts opts[2]; setup_locale(); secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); if (argc < 8 + 7 * 2) errx(1, "Usage: mkgossip update-opts-1 update-opts-2\n" "Where is:\n" " \n" " \n" " \n" " \n" " \n" " \n" " "); opt_register_noarg("-v|--verbose", opt_set_bool, &verbose, "Increase verbosity"); opt_parse(&argc, argv, opt_log_stderr_exit); argnum = 1; if (!short_channel_id_from_str(argv[argnum], strlen(argv[argnum]), &scid)) errx(1, "Bad scid"); argnum++; /* Don't do endian-reversing insanity here! */ if (!hex_decode(argv[argnum], strlen(argv[argnum]), &chainhash, sizeof(chainhash))) errx(1, "Parsing chainhash"); argnum++; if (!hex_decode(argv[argnum], strlen(argv[argnum]), &node_privkey[0], sizeof(node_privkey[0]))) errx(1, "Parsing node-privkey1"); argnum++; if (!hex_decode(argv[argnum], strlen(argv[argnum]), &node_privkey[1], sizeof(node_privkey[2]))) errx(1, "Parsing node-privkey2"); argnum++; if (!hex_decode(argv[argnum], strlen(argv[argnum]), &funding_privkey[0], sizeof(funding_privkey[0]))) errx(1, "Parsing funding-privkey1"); argnum++; if (!hex_decode(argv[argnum], strlen(argv[argnum]), &funding_privkey[1], sizeof(funding_privkey[2]))) errx(1, "Parsing funding-privkey2"); argnum++; features = tal_hexdata(NULL, argv[argnum], strlen(argv[argnum])); if (!features) errx(1, "Parsing hexfeatures"); argnum++; argnum += parse_options(argv + argnum, &opts[0], "update-opts1"); argnum += parse_options(argv + argnum, &opts[1], "update-opts2"); if (!pubkey_from_privkey(&node_privkey[0], &node[0]) || !pubkey_from_privkey(&node_privkey[1], &node[1]) || !pubkey_from_privkey(&funding_privkey[0], &bitcoin[0]) || !pubkey_from_privkey(&funding_privkey[1], &bitcoin[1])) errx(1, "Bad privkeys"); lesser_key = pubkey_idx(&node[0], &node[1]); node_id_from_pubkey(&nodeid[0], &node[0]); node_id_from_pubkey(&nodeid[1], &node[1]); /* First make msg with dummy sigs. */ memset(nodesig, 0, sizeof(nodesig)); memset(bitcoinsig, 0, sizeof(bitcoinsig)); cannounce = towire_channel_announcement(NULL, &nodesig[lesser_key], &nodesig[!lesser_key], &bitcoinsig[lesser_key], &bitcoinsig[!lesser_key], features, &chainhash, &scid, &nodeid[lesser_key], &nodeid[!lesser_key], &bitcoin[lesser_key], &bitcoin[!lesser_key]); sha256_double(&hash, cannounce + channel_announcement_offset, tal_count(cannounce) - channel_announcement_offset); sign_hash(&node_privkey[0], &hash, &nodesig[0]); sign_hash(&funding_privkey[0], &hash, &bitcoinsig[0]); sign_hash(&node_privkey[1], &hash, &nodesig[1]); sign_hash(&funding_privkey[1], &hash, &bitcoinsig[1]); printf("type=channel_announcement\n"); printf(" node_signature_1=%s\n", sig_notation(&node_privkey[lesser_key], &hash, &nodesig[lesser_key])); printf(" node_signature_2=%s\n", sig_notation(&node_privkey[!lesser_key], &hash, &nodesig[!lesser_key])); printf(" bitcoin_signature_1=%s\n", sig_notation(&funding_privkey[lesser_key], &hash, &bitcoinsig[lesser_key])); printf(" bitcoin_signature_2=%s\n", sig_notation(&funding_privkey[!lesser_key], &hash, &bitcoinsig[!lesser_key])); printf(" features=%s\n", tal_hex(NULL, features)); printf(" chain_hash=%s\n", tal_hexstr(NULL, &chainhash, sizeof(chainhash))); printf(" short_channel_id=%s\n", short_channel_id_to_str(NULL, &scid)); printf(" node_id_1=%s\n", node_id_to_hexstr(NULL, &nodeid[lesser_key])); printf(" node_id_2=%s\n", node_id_to_hexstr(NULL, &nodeid[!lesser_key])); printf(" bitcoin_key_1=%s\n", pubkey_to_hexstr(NULL, &bitcoin[lesser_key])); printf(" bitcoin_key_2=%s\n", pubkey_to_hexstr(NULL, &bitcoin[!lesser_key])); printf("\n#Node 1:\n"); print_update(&chainhash, &scid, &opts[0], lesser_key == 0, &node_privkey[0]); print_nannounce(&nodeid[0], &opts[0], &node_privkey[0]); printf("\n#Node 2:\n"); print_update(&chainhash, &scid, &opts[1], lesser_key == 1, &node_privkey[1]); print_nannounce(&nodeid[1], &opts[1], &node_privkey[1]); return 0; }