diff --git a/lightningd/sphinx.c b/lightningd/sphinx.c index e09eb02b8..f513491c8 100644 --- a/lightningd/sphinx.c +++ b/lightningd/sphinx.c @@ -330,9 +330,35 @@ static struct hop_params *generate_hop_params( return params; } +static void serialize_hop_data(tal_t *ctx, u8 *dst, const struct hop_data *data) +{ + u8 *buf = tal_arr(ctx, u8, 0); + towire_u8(&buf, data->realm); + towire_short_channel_id(&buf, &data->channel_id); + towire_u32(&buf, data->amt_forward); + towire_u32(&buf, data->outgoing_cltv); + towire_pad(&buf, 16); + towire(&buf, data->hmac, SECURITY_PARAMETER); + memcpy(dst, buf, tal_len(buf)); + tal_free(buf); +} + +static void deserialize_hop_data(struct hop_data *data, const u8 *src) +{ + const u8 *cursor = src; + size_t max = HOP_DATA_SIZE; + data->realm = fromwire_u8(&cursor, &max); + fromwire_short_channel_id(&cursor, &max, &data->channel_id); + data->amt_forward = fromwire_u32(&cursor, &max); + data->outgoing_cltv = fromwire_u32(&cursor, &max); + fromwire_pad(&cursor, &max, 16); + fromwire(&cursor, &max, &data->hmac, SECURITY_PARAMETER); +} + struct onionpacket *create_onionpacket( const tal_t *ctx, struct pubkey *path, + struct hop_data hops_data[], const u8 *sessionkey, const u8 *assocdata, const size_t assocdatalen @@ -340,7 +366,7 @@ struct onionpacket *create_onionpacket( { struct onionpacket *packet = talz(ctx, struct onionpacket); int i, num_hops = tal_count(path); - u8 filler[2 * (num_hops - 1) * SECURITY_PARAMETER]; + u8 filler[(num_hops - 1) * HOP_DATA_SIZE]; struct keyset keys; u8 nextaddr[20], nexthmac[SECURITY_PARAMETER]; u8 stream[ROUTING_INFO_SIZE]; @@ -353,22 +379,22 @@ struct onionpacket *create_onionpacket( memset(nexthmac, 0, 20); memset(packet->routinginfo, 0, ROUTING_INFO_SIZE); - generate_header_padding(filler, sizeof(filler), 2 * SECURITY_PARAMETER, + generate_header_padding(filler, sizeof(filler), HOP_DATA_SIZE, "rho", 3, num_hops, params); for (i = num_hops - 1; i >= 0; i--) { + memcpy(hops_data[i].hmac, nexthmac, SECURITY_PARAMETER); generate_key_set(params[i].secret, &keys); generate_cipher_stream(stream, keys.rho, ROUTING_INFO_SIZE); /* Rightshift mix-header by 2*SECURITY_PARAMETER */ - memmove(packet->routinginfo + 2 * SECURITY_PARAMETER, packet->routinginfo, - ROUTING_INFO_SIZE - 2 * SECURITY_PARAMETER); - memcpy(packet->routinginfo, nextaddr, SECURITY_PARAMETER); - memcpy(packet->routinginfo + SECURITY_PARAMETER, nexthmac, SECURITY_PARAMETER); + memmove(packet->routinginfo + HOP_DATA_SIZE, packet->routinginfo, + ROUTING_INFO_SIZE - HOP_DATA_SIZE); + serialize_hop_data(packet, packet->routinginfo, &hops_data[i]); xorbytes(packet->routinginfo, packet->routinginfo, stream, ROUTING_INFO_SIZE); if (i == num_hops - 1) { - size_t len = (NUM_MAX_HOPS - num_hops + 1) * 2 * SECURITY_PARAMETER; + size_t len = (NUM_MAX_HOPS - num_hops + 1) * HOP_DATA_SIZE; memcpy(packet->routinginfo + len, filler, sizeof(filler)); } @@ -398,7 +424,7 @@ struct route_step *process_onionpacket( struct keyset keys; u8 blind[BLINDING_FACTOR_SIZE]; u8 stream[NUM_STREAM_BYTES]; - u8 paddedheader[ROUTING_INFO_SIZE + 2 * SECURITY_PARAMETER]; + u8 paddedheader[ROUTING_INFO_SIZE + HOP_DATA_SIZE]; step->next = talz(step, struct onionpacket); step->next->version = msg->version; @@ -421,12 +447,12 @@ struct route_step *process_onionpacket( compute_blinding_factor(&msg->ephemeralkey, shared_secret, blind); if (!blind_group_element(&step->next->ephemeralkey, &msg->ephemeralkey, blind)) return tal_free(step); - memcpy(&step->next->nexthop, paddedheader, SECURITY_PARAMETER); - memcpy(&step->next->mac, - paddedheader + SECURITY_PARAMETER, - SECURITY_PARAMETER); - memcpy(&step->next->routinginfo, paddedheader + 2 * SECURITY_PARAMETER, ROUTING_INFO_SIZE); + deserialize_hop_data(&step->hop_data, paddedheader); + + memcpy(&step->next->mac, step->hop_data.hmac, SECURITY_PARAMETER); + + memcpy(&step->next->routinginfo, paddedheader + HOP_DATA_SIZE, ROUTING_INFO_SIZE); if (memeqzero(step->next->mac, sizeof(step->next->mac))) { step->nextcase = ONION_END; diff --git a/lightningd/sphinx.h b/lightningd/sphinx.h index 67b2a0674..4ab5e82f0 100644 --- a/lightningd/sphinx.h +++ b/lightningd/sphinx.h @@ -9,11 +9,12 @@ #include #include #include +#include #define SECURITY_PARAMETER 20 #define NUM_MAX_HOPS 20 -#define HOP_DATA_SIZE 40 -#define ROUTING_INFO_SIZE (HOP_DATA_SIZE * SECURITY_PARAMETER) +#define HOP_DATA_SIZE 53 +#define ROUTING_INFO_SIZE (HOP_DATA_SIZE * NUM_MAX_HOPS) #define TOTAL_PACKET_SIZE (1 + 33 + SECURITY_PARAMETER + ROUTING_INFO_SIZE) struct onionpacket { @@ -34,23 +35,35 @@ enum route_next_case { /* BOLT #4: * - * The format of the per-hop-payload for a version 0 packet is as follows: + * The hops_data field is a structure that holds obfuscated versions of the next hop's address, transfer information and the associated HMAC. It is 1060 bytes long, and has the following structure: + ``` -+----------------+--------------------------+-------------------------------+--------------------------------------------+ -| realm (1 byte) | amt_to_forward (8 bytes) | outgoing_cltv_value (4 bytes) | unused_with_v0_version_on_header (7 bytes) | -+----------------+--------------------------+-------------------------------+--------------------------------------------+ ++-----------+-------------+----------+-----------+-------------+----------+-----------+ +| n_1 realm | n_1 per-hop | n_1 HMAC | n_2 realm | n_2 per-hop | n_2 HMAC | ...filler | ++-----------+-------------+----------+----------+--------------+----------+------------+ +``` + +The realm byte determines the format of the per-hop; so far only realm 0 is defined, and for that, the per-hop format is: + +``` ++----------------------+--------------------------+-------------------------------+--------------------+ +| channel_id (8 bytes) | amt_to_forward (4 bytes) | outgoing_cltv_value (4 bytes) | padding (16 bytes) | ++----------------------+--------------------------+-------------------------------+--------------------+ ``` */ -struct hoppayload { +struct hop_data { u8 realm; - u64 amt_to_forward; - u32 outgoing_cltv_value; - u8 unused_with_v0_version_on_header[7]; + struct short_channel_id channel_id; + u32 amt_forward; + u32 outgoing_cltv; + /* Padding omitted, will be zeroed */ + u8 hmac[SECURITY_PARAMETER]; }; struct route_step { enum route_next_case nextcase; struct onionpacket *next; + struct hop_data hop_data; }; /** @@ -69,6 +82,7 @@ struct route_step { struct onionpacket *create_onionpacket( const tal_t * ctx, struct pubkey path[], + struct hop_data hops_data[], const u8 * sessionkey, const u8 *assocdata, const size_t assocdatalen diff --git a/test/test_sphinx.c b/test/test_sphinx.c index 4757971e7..b12cca9cd 100644 --- a/test/test_sphinx.c +++ b/test/test_sphinx.c @@ -131,6 +131,7 @@ int main(int argc, char **argv) struct pubkey *path = tal_arr(ctx, struct pubkey, num_hops); u8 privkeys[argc - 1][32]; u8 sessionkey[32]; + struct hop_data hops_data[num_hops]; memset(&sessionkey, 'A', sizeof(sessionkey)); @@ -141,9 +142,13 @@ int main(int argc, char **argv) return 1; } + for (i=0; i