sphinx: Using hop_data to serialize per-hop information into onion

Signed-off-by: Christian Decker <decker.christian@gmail.com>
This commit is contained in:
Christian Decker 2017-04-08 12:16:56 -07:00
parent 752f884c23
commit 83e89f0fe5
3 changed files with 68 additions and 23 deletions

View File

@ -330,9 +330,35 @@ static struct hop_params *generate_hop_params(
return 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( struct onionpacket *create_onionpacket(
const tal_t *ctx, const tal_t *ctx,
struct pubkey *path, struct pubkey *path,
struct hop_data hops_data[],
const u8 *sessionkey, const u8 *sessionkey,
const u8 *assocdata, const u8 *assocdata,
const size_t assocdatalen const size_t assocdatalen
@ -340,7 +366,7 @@ struct onionpacket *create_onionpacket(
{ {
struct onionpacket *packet = talz(ctx, struct onionpacket); struct onionpacket *packet = talz(ctx, struct onionpacket);
int i, num_hops = tal_count(path); 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; struct keyset keys;
u8 nextaddr[20], nexthmac[SECURITY_PARAMETER]; u8 nextaddr[20], nexthmac[SECURITY_PARAMETER];
u8 stream[ROUTING_INFO_SIZE]; u8 stream[ROUTING_INFO_SIZE];
@ -353,22 +379,22 @@ struct onionpacket *create_onionpacket(
memset(nexthmac, 0, 20); memset(nexthmac, 0, 20);
memset(packet->routinginfo, 0, ROUTING_INFO_SIZE); 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); "rho", 3, num_hops, params);
for (i = num_hops - 1; i >= 0; i--) { for (i = num_hops - 1; i >= 0; i--) {
memcpy(hops_data[i].hmac, nexthmac, SECURITY_PARAMETER);
generate_key_set(params[i].secret, &keys); generate_key_set(params[i].secret, &keys);
generate_cipher_stream(stream, keys.rho, ROUTING_INFO_SIZE); generate_cipher_stream(stream, keys.rho, ROUTING_INFO_SIZE);
/* Rightshift mix-header by 2*SECURITY_PARAMETER */ /* Rightshift mix-header by 2*SECURITY_PARAMETER */
memmove(packet->routinginfo + 2 * SECURITY_PARAMETER, packet->routinginfo, memmove(packet->routinginfo + HOP_DATA_SIZE, packet->routinginfo,
ROUTING_INFO_SIZE - 2 * SECURITY_PARAMETER); ROUTING_INFO_SIZE - HOP_DATA_SIZE);
memcpy(packet->routinginfo, nextaddr, SECURITY_PARAMETER); serialize_hop_data(packet, packet->routinginfo, &hops_data[i]);
memcpy(packet->routinginfo + SECURITY_PARAMETER, nexthmac, SECURITY_PARAMETER);
xorbytes(packet->routinginfo, packet->routinginfo, stream, ROUTING_INFO_SIZE); xorbytes(packet->routinginfo, packet->routinginfo, stream, ROUTING_INFO_SIZE);
if (i == num_hops - 1) { 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)); memcpy(packet->routinginfo + len, filler, sizeof(filler));
} }
@ -398,7 +424,7 @@ struct route_step *process_onionpacket(
struct keyset keys; struct keyset keys;
u8 blind[BLINDING_FACTOR_SIZE]; u8 blind[BLINDING_FACTOR_SIZE];
u8 stream[NUM_STREAM_BYTES]; 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 = talz(step, struct onionpacket);
step->next->version = msg->version; step->next->version = msg->version;
@ -421,12 +447,12 @@ struct route_step *process_onionpacket(
compute_blinding_factor(&msg->ephemeralkey, shared_secret, blind); compute_blinding_factor(&msg->ephemeralkey, shared_secret, blind);
if (!blind_group_element(&step->next->ephemeralkey, &msg->ephemeralkey, blind)) if (!blind_group_element(&step->next->ephemeralkey, &msg->ephemeralkey, blind))
return tal_free(step); 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))) { if (memeqzero(step->next->mac, sizeof(step->next->mac))) {
step->nextcase = ONION_END; step->nextcase = ONION_END;

View File

@ -9,11 +9,12 @@
#include <ccan/tal/tal.h> #include <ccan/tal/tal.h>
#include <secp256k1.h> #include <secp256k1.h>
#include <sodium/randombytes.h> #include <sodium/randombytes.h>
#include <wire/wire.h>
#define SECURITY_PARAMETER 20 #define SECURITY_PARAMETER 20
#define NUM_MAX_HOPS 20 #define NUM_MAX_HOPS 20
#define HOP_DATA_SIZE 40 #define HOP_DATA_SIZE 53
#define ROUTING_INFO_SIZE (HOP_DATA_SIZE * SECURITY_PARAMETER) #define ROUTING_INFO_SIZE (HOP_DATA_SIZE * NUM_MAX_HOPS)
#define TOTAL_PACKET_SIZE (1 + 33 + SECURITY_PARAMETER + ROUTING_INFO_SIZE) #define TOTAL_PACKET_SIZE (1 + 33 + SECURITY_PARAMETER + ROUTING_INFO_SIZE)
struct onionpacket { struct onionpacket {
@ -34,23 +35,35 @@ enum route_next_case {
/* BOLT #4: /* 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; u8 realm;
u64 amt_to_forward; struct short_channel_id channel_id;
u32 outgoing_cltv_value; u32 amt_forward;
u8 unused_with_v0_version_on_header[7]; u32 outgoing_cltv;
/* Padding omitted, will be zeroed */
u8 hmac[SECURITY_PARAMETER];
}; };
struct route_step { struct route_step {
enum route_next_case nextcase; enum route_next_case nextcase;
struct onionpacket *next; struct onionpacket *next;
struct hop_data hop_data;
}; };
/** /**
@ -69,6 +82,7 @@ struct route_step {
struct onionpacket *create_onionpacket( struct onionpacket *create_onionpacket(
const tal_t * ctx, const tal_t * ctx,
struct pubkey path[], struct pubkey path[],
struct hop_data hops_data[],
const u8 * sessionkey, const u8 * sessionkey,
const u8 *assocdata, const u8 *assocdata,
const size_t assocdatalen const size_t assocdatalen

View File

@ -131,6 +131,7 @@ int main(int argc, char **argv)
struct pubkey *path = tal_arr(ctx, struct pubkey, num_hops); struct pubkey *path = tal_arr(ctx, struct pubkey, num_hops);
u8 privkeys[argc - 1][32]; u8 privkeys[argc - 1][32];
u8 sessionkey[32]; u8 sessionkey[32];
struct hop_data hops_data[num_hops];
memset(&sessionkey, 'A', sizeof(sessionkey)); memset(&sessionkey, 'A', sizeof(sessionkey));
@ -141,9 +142,13 @@ int main(int argc, char **argv)
return 1; return 1;
} }
for (i=0; i<num_hops; i++) {
memset(&hops_data[i], 'A', sizeof(hops_data[i]));
}
struct onionpacket *res = create_onionpacket(ctx, struct onionpacket *res = create_onionpacket(ctx,
path, path,
hops_data,
sessionkey, sessionkey,
assocdata, assocdata,
sizeof(assocdata)); sizeof(assocdata));