diff --git a/common/Makefile b/common/Makefile index b5a1591e9..28751e7bf 100644 --- a/common/Makefile +++ b/common/Makefile @@ -71,6 +71,7 @@ COMMON_SRC_NOGEN := \ common/onion_decode.c \ common/onion_encode.c \ common/onionreply.c \ + common/onion_message.c \ common/onion_message_parse.c \ common/peer_billboard.c \ common/peer_failed.c \ diff --git a/common/onion_message.c b/common/onion_message.c new file mode 100644 index 000000000..98e5b87d8 --- /dev/null +++ b/common/onion_message.c @@ -0,0 +1,228 @@ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct tlv_encrypted_data_tlv **new_encdata_tlvs(const tal_t *ctx, + const struct pubkey *ids, + const struct short_channel_id **scids) +{ + struct tlv_encrypted_data_tlv **etlvs; + + etlvs = tal_arr(ctx, struct tlv_encrypted_data_tlv *, tal_count(ids)); + for (size_t i = 0; i < tal_count(etlvs); i++) { + etlvs[i] = tlv_encrypted_data_tlv_new(etlvs); + if (i+1 < tal_count(scids) && scids[i+1]) { + etlvs[i]->short_channel_id = tal_dup(etlvs[i], + struct short_channel_id, + scids[i+1]); + } else if (i + 1 < tal_count(ids)) { + etlvs[i]->next_node_id = tal_dup(etlvs[i], + struct pubkey, + &ids[i+1]); + } + } + return etlvs; +} + +/* We can extract nodeid from ids[], but usually we can get it from the + * previous next_node_id. */ +static const struct pubkey * +get_nodeid(const struct tlv_encrypted_data_tlv **tlvs, + const struct pubkey *ids, + size_t i) +{ + if (i == 0) + return &ids[0]; + + if (tlvs[i-1]->next_node_id == NULL) { + /* If you didn't set next_node_id you have to set + * short_channel_id! */ + assert(tlvs[i-1]->short_channel_id); + assert(i < tal_count(ids)); + return &ids[i]; + } + + return tlvs[i-1]->next_node_id; +} + +/* Stage 1: tlv_encrypted_data_tlv[] -> struct blinded_path. + * Optional array of node_ids, consulted iff tlv uses scid in one entry. */ +struct blinded_path *blinded_path_from_encdata_tlvs(const tal_t *ctx, + const struct tlv_encrypted_data_tlv **tlvs, + const struct pubkey *ids) +{ + struct privkey first_blinding, blinding_iter; + struct blinded_path *path; + size_t nhops = tal_count(ids); + const struct pubkey *nodeid; + + path = tal(ctx, struct blinded_path); + + assert(nhops > 0); + assert(tal_count(ids) > 0); + + randombytes_buf(&first_blinding, sizeof(first_blinding)); + if (!pubkey_from_privkey(&first_blinding, &path->blinding)) + abort(); + sciddir_or_pubkey_from_pubkey(&path->first_node_id, &ids[0]); + + path->path = tal_arr(ctx, struct onionmsg_hop *, nhops); + + blinding_iter = first_blinding; + for (size_t i = 0; i < nhops; i++) { + nodeid = get_nodeid(tlvs, ids, i); + + path->path[i] = tal(path->path, struct onionmsg_hop); + path->path[i]->encrypted_recipient_data + = encrypt_tlv_encrypted_data(path->path[i], + &blinding_iter, + nodeid, + tlvs[i], + &blinding_iter, + &path->path[i]->blinded_node_id); + } + + return path; +} + +/* Stage 2: turn struct blinded_path into array of tlv_onionmsg_tlv. + * You normally then add fields to the final tlv_onionmsg_tlv. */ +struct tlv_onionmsg_tlv **onionmsg_tlvs_from_blinded_path(const tal_t *ctx, + const struct blinded_path *bpath) +{ + size_t nhops = tal_count(bpath->path); + struct tlv_onionmsg_tlv **otlvs = tal_arr(ctx, struct tlv_onionmsg_tlv *, nhops); + + for (size_t i = 0; i < nhops; i++) { + otlvs[i] = tlv_onionmsg_tlv_new(otlvs); + otlvs[i]->encrypted_recipient_data + = tal_dup_talarr(otlvs[i], u8, + bpath->path[i]->encrypted_recipient_data); + } + + return otlvs; +} + +/* Stage 3: linearize each struct tlv_onionmsg_tlv into sphinx_hops (taking ids from bpath) */ +struct sphinx_hop **onionmsg_tlvs_to_hops(const tal_t *ctx, + const struct blinded_path *bpath, + const struct tlv_onionmsg_tlv **tlvs) +{ + size_t nhops = tal_count(tlvs); + struct sphinx_hop **hops = tal_arr(ctx, struct sphinx_hop *, nhops); + + assert(tal_count(bpath->path) == nhops); + for (size_t i = 0; i < nhops; i++) { + u8 *payload; + hops[i] = tal(hops, struct sphinx_hop); + hops[i]->pubkey = bpath->path[i]->blinded_node_id; + /* We use a temporary here since ->raw_payload is const */ + payload = tal_arr(hops[i], u8, 0); + towire_tlv_onionmsg_tlv(&payload, tlvs[i]); + hops[i]->raw_payload = payload; + } + + return hops; +} + +struct blinded_path *incoming_message_blinded_path(const tal_t *ctx, + const struct pubkey *ids, + const struct short_channel_id **scids, + const struct secret *path_secret) +{ + struct tlv_encrypted_data_tlv **etlvs; + size_t nhops = tal_count(ids); + + assert(nhops > 0); + etlvs = new_encdata_tlvs(tmpctx, ids, scids); + + /* Put path_secret into final hop (us) */ + etlvs[nhops-1]->path_id = tal_dup_arr(etlvs[nhops-1], u8, + path_secret->data, + ARRAY_SIZE(path_secret->data), 0); + + return blinded_path_from_encdata_tlvs(ctx, + cast_const2(const struct tlv_encrypted_data_tlv **, etlvs), + ids); +} + +static void extend_blinded_path(struct blinded_path *bpath, + const struct onionmsg_hop *hop) +{ + struct onionmsg_hop *newhop = tal(bpath->path, struct onionmsg_hop); + newhop->blinded_node_id = hop->blinded_node_id; + newhop->encrypted_recipient_data = tal_dup_talarr(newhop, u8, hop->encrypted_recipient_data); + tal_arr_expand(&bpath->path, newhop); +} + +struct onion_message *outgoing_onion_message(const tal_t *ctx, + const struct pubkey *ids, + const struct short_channel_id **scids, + const struct blinded_path *their_path, + struct tlv_onionmsg_tlv *final_tlv STEALS) +{ + struct onion_message *omsg; + struct blinded_path *our_path; + const struct blinded_path *combined_path; + struct tlv_encrypted_data_tlv **etlvs = new_encdata_tlvs(tmpctx, ids, scids); + struct tlv_onionmsg_tlv **otlvs; + + assert(tal_count(ids) > 0); + + if (their_path) { + struct tlv_encrypted_data_tlv *pre_final; + + /* Path must lead to blinded path! */ + if (their_path->first_node_id.is_pubkey) + assert(pubkey_eq(&ids[tal_count(ids)-1], &their_path->first_node_id.pubkey)); + + /* If we don't actually have any path, it's all them. */ + if (tal_count(ids) == 1) { + combined_path = their_path; + goto wrap; + } + + /* We need to tell last hop to hand blinded_path blinding for next hop */ + pre_final = etlvs[tal_count(ids)-2]; + pre_final->next_blinding_override = tal_dup(pre_final, + struct pubkey, + &their_path->blinding); + } + + our_path = blinded_path_from_encdata_tlvs(tmpctx, + cast_const2(const struct tlv_encrypted_data_tlv **, etlvs), + ids); + + /* Extend with their blinded path if there is one */ + if (their_path) { + /* Remove final one, since it's actually the first one in blinded path. */ + tal_resize(&our_path->path, tal_count(our_path->path)-1); + for (size_t i = 0; i < tal_count(their_path->path); i++) + extend_blinded_path(our_path, their_path->path[i]); + } + + combined_path = our_path; + +wrap: + /* Now wrap in onionmsg_tlvs */ + otlvs = onionmsg_tlvs_from_blinded_path(tmpctx, combined_path); + + /* Transfer encrypted blob into final tlv, and use it to replace last tlv */ + final_tlv->encrypted_recipient_data = tal_steal(final_tlv, otlvs[tal_count(otlvs)-1]->encrypted_recipient_data); + tal_free(otlvs[tal_count(otlvs)-1]); + otlvs[tal_count(otlvs)-1] = tal_steal(otlvs, final_tlv); + + /* Now populate the onion message to return */ + omsg = tal(ctx, struct onion_message); + omsg->first_blinding = combined_path->blinding; + omsg->hops = onionmsg_tlvs_to_hops(omsg, combined_path, + cast_const2(const struct tlv_onionmsg_tlv **, otlvs)); + return omsg; +} diff --git a/common/onion_message.h b/common/onion_message.h new file mode 100644 index 000000000..efa05c4cb --- /dev/null +++ b/common/onion_message.h @@ -0,0 +1,130 @@ +#ifndef LIGHTNING_COMMON_ONION_MESSAGE_H +#define LIGHTNING_COMMON_ONION_MESSAGE_H +#include "config.h" +#include +#include +#include + +struct tlv_onionmsg_tlv; +struct secret; + +/* Onion messages are kind of complicated, so read carefully! + * + * An onion message is an array of struct tlv_onionmsg_tlv: + * encrypted struct tlv_encrypted_data_tlv: + * encrypted_recipient_data + * + * The final entry can also have unencrypted fields: + * struct blinded_path *reply_path; + * u8 *invoice_request; + * u8 *invoice; + * u8 *invoice_error; + * + * The struct tlv_encrypted_data_tlv contains the interesting things: + * + * Intermediate nodes: + * short_channel_id/next_node_id (always) + * next_blinding_override (optional) + * payment_relay/payment_constraints (required, for payments only) + * allowed_features (optional) + * + * Final nodes: + * path_id (so it can tell blinded path was correctly used). + */ + +/* Low level routines: */ + +/** + * Stage 0: populate tlv_encrypted_data_tlv[] array. + * @ctx: tal context + * @ids: array of pubkeys defining path destinations + * @scids: optional array of scids: if non-NULL, use this instead of pubkey for + * next hop values. + * + * This simply populates the short_channel_id/next_node_id fields; you will want to + * add others. + */ +struct tlv_encrypted_data_tlv **new_encdata_tlvs(const tal_t *ctx, + const struct pubkey *ids, + const struct short_channel_id **scids); + +/** + * Stage 1: tlv_encrypted_data_tlv[] -> struct blinded_path. + * @ctx: tal context + * @tlvs: tlvs to be encrypted + * @ids: array of pubkeys. + * + * ids[0] needs to be first node id, but rest don't have to be there unless + * a tlv uses short_channel_id instead of next_node_id. + * + * You can turn the first_node_id into an scidd after if you want to. + */ +struct blinded_path *blinded_path_from_encdata_tlvs(const tal_t *ctx, + const struct tlv_encrypted_data_tlv **tlvs, + const struct pubkey *ids); + +/** + * Stage 2: turn struct blinded_path into array of tlv_onionmsg_tlv. + * @ctx: tal context + * @bpath: path containing the encrypted blobs. + * + * You normally then add payload fields to the final tlv_onionmsg_tlv. + */ +struct tlv_onionmsg_tlv **onionmsg_tlvs_from_blinded_path(const tal_t *ctx, + const struct blinded_path *bpath); + +/** + * Stage 3: linearize each struct tlv_onionmsg_tlv into onionmsg_hops + * @ctx: tal context + * @bpath: the path (for the pubkeys) + * @tlvs: the tlvs for each hop. + * + * This is the format the sphinx wants to encode the actual onion message. + */ +struct sphinx_hop **onionmsg_tlvs_to_hops(const tal_t *ctx, + const struct blinded_path *bpath, + const struct tlv_onionmsg_tlv **tlvs); + + +/* Stage 4: turn into sphinx_hop * into linear onionmsg (e.g. via injectonionmessage, + * or directly using common/sphinx.c) */ + +/* Higher level helpers. */ + +/** + * incoming_message_blinded_path - create incoming blinded path for messages. + * @ctx: context to tallocate off + * @ids: array of node ids. + * @scids: optional, if these are set, use these for directions instead of node ids. + * @path_secret: put this into final entry, so we can verify. + */ +struct blinded_path *incoming_message_blinded_path(const tal_t *ctx, + const struct pubkey *ids, + const struct short_channel_id **scids, + const struct secret *path_secret); + + +/* A ready-to-be-encrypted-and-sent onion message. */ +struct onion_message { + struct pubkey first_blinding; + struct sphinx_hop **hops; +}; + +/** + * outgoing_message_tlvs - create encrypted blobs to send msg + * @ctx: context to tallocate off + * @ids: array of node ids (first is our peer, must be at least one). + * @scids: optional, if these are set, use these for directions instead of node ids. + * @their_path: blinded path they told us to use for reply (or NULL) + * @final_tlv: extra fields to put in final tlv (consumed) + * + * If @their_path is set, the final @ids entry must be @their_path->first_node_id. + * We cannot check this if their_path->first_node_id is not a pubkey, of course. + */ +struct onion_message *outgoing_onion_message(const tal_t *ctx, + const struct pubkey *ids, + const struct short_channel_id **scids, + const struct blinded_path *their_path, + struct tlv_onionmsg_tlv *final_tlv STEALS); + +#endif /* LIGHTNING_COMMON_ONION_MESSAGE_H */