mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-22 22:45:27 +01:00
sphinx: Treat compressed onions as a standalone struct
Expands the interface to play with onions a bit more. Potentially a bit slower due to allocations, but that's a small price to pay. It also allows us to avoid serializing a compressed onion to `u8*` if we process it right away.
This commit is contained in:
parent
fd37c5b672
commit
e79cda8c9a
3 changed files with 114 additions and 19 deletions
102
common/sphinx.c
102
common/sphinx.c
|
@ -786,26 +786,96 @@ u8 *unwrap_onionreply(const tal_t *ctx,
|
|||
return final;
|
||||
}
|
||||
|
||||
u8 *sphinx_decompress(const tal_t *ctx, const u8 *compressed,
|
||||
struct secret *shared_secret)
|
||||
struct onionpacket *sphinx_decompress(const tal_t *ctx,
|
||||
const struct sphinx_compressed_onion *src,
|
||||
const struct secret *shared_secret)
|
||||
{
|
||||
size_t compressedlen = tal_bytelen(compressed);
|
||||
size_t prefill_size = TOTAL_PACKET_SIZE - compressedlen;
|
||||
u8 *dst;
|
||||
struct onionpacket *res = tal(ctx, struct onionpacket);
|
||||
size_t srclen = tal_bytelen(src->routinginfo);
|
||||
size_t prefill_size = ROUTING_INFO_SIZE - srclen;
|
||||
|
||||
res->version = src->version;
|
||||
res->ephemeralkey = src->ephemeralkey;
|
||||
memcpy(res->mac, src->mac, HMAC_SIZE);
|
||||
|
||||
/* Decompress routinginfo by copying the unmodified prefix, setting
|
||||
* the compressed suffix to 0x00 bytes and then xoring the obfuscation
|
||||
* stream in place. */
|
||||
memset(res->routinginfo, 0, ROUTING_INFO_SIZE);
|
||||
memcpy(res->routinginfo, src->routinginfo, srclen);
|
||||
sphinx_prefill_stream_xor(res->routinginfo + srclen, prefill_size,
|
||||
shared_secret);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
struct sphinx_compressed_onion *
|
||||
sphinx_compress(const tal_t *ctx, const struct onionpacket *packet,
|
||||
const struct sphinx_path *path)
|
||||
{
|
||||
struct sphinx_compressed_onion *res;
|
||||
size_t payloads_size = sphinx_path_payloads_size(path);
|
||||
|
||||
/* We can't compress an onion that doesn't have a rendez-vous node. */
|
||||
if (path->rendezvous_id)
|
||||
return NULL;
|
||||
|
||||
res = tal(ctx, struct sphinx_compressed_onion);
|
||||
res->version = packet->version;
|
||||
res->ephemeralkey = packet->ephemeralkey;
|
||||
memcpy(res->mac, packet->mac, HMAC_SIZE);
|
||||
|
||||
res->routinginfo = tal_arr(res, u8, payloads_size);
|
||||
memcpy(res->routinginfo, packet->routinginfo, payloads_size);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
u8 *sphinx_compressed_onion_serialize(const tal_t *ctx, const struct sphinx_compressed_onion *onion)
|
||||
{
|
||||
size_t routelen = tal_bytelen(onion->routinginfo);
|
||||
size_t len = VERSION_SIZE + PUBKEY_SIZE + routelen + HMAC_SIZE;
|
||||
u8 *dst = tal_arr(ctx, u8, len);
|
||||
u8 der[PUBKEY_CMPR_LEN];
|
||||
int p = 0;
|
||||
|
||||
assert(prefill_size >= 0);
|
||||
assert(compressedlen >= VERSION_SIZE + PUBKEY_SIZE + HMAC_SIZE);
|
||||
dst = tal_arrz(ctx, u8, TOTAL_PACKET_SIZE);
|
||||
write_buffer(
|
||||
dst, compressed,
|
||||
VERSION_SIZE + PUBKEY_SIZE + ROUTING_INFO_SIZE - prefill_size, &p);
|
||||
pubkey_to_der(der, &onion->ephemeralkey);
|
||||
|
||||
/* We can just XOR here since we initialized the array with zeros. */
|
||||
sphinx_prefill_stream_xor(dst + p, prefill_size, shared_secret);
|
||||
p += prefill_size;
|
||||
write_buffer(dst, &onion->version, VERSION_SIZE, &p);
|
||||
write_buffer(dst, der, PUBKEY_SIZE, &p);
|
||||
write_buffer(dst, onion->routinginfo, routelen, &p);
|
||||
write_buffer(dst, onion->mac, HMAC_SIZE, &p);
|
||||
|
||||
assert(p == len);
|
||||
return dst;
|
||||
}
|
||||
|
||||
struct sphinx_compressed_onion *
|
||||
sphinx_compressed_onion_deserialize(const tal_t *ctx, const u8 *src)
|
||||
{
|
||||
size_t srclen = tal_bytelen(src);
|
||||
size_t routelen = srclen - VERSION_SIZE - PUBKEY_SIZE - HMAC_SIZE;
|
||||
struct sphinx_compressed_onion *dst =
|
||||
tal(ctx, struct sphinx_compressed_onion);
|
||||
int p = 0;
|
||||
u8 ephkey[PUBKEY_SIZE];
|
||||
|
||||
assert(srclen <= TOTAL_PACKET_SIZE);
|
||||
|
||||
read_buffer(&dst->version, src, 1, &p);
|
||||
if (dst->version != 0x00)
|
||||
return tal_free(dst);
|
||||
|
||||
read_buffer(ephkey, src, PUBKEY_SIZE, &p);
|
||||
|
||||
if (!pubkey_from_der(ephkey, PUBKEY_SIZE, &dst->ephemeralkey)) {
|
||||
return tal_free(dst);
|
||||
}
|
||||
|
||||
dst->routinginfo = tal_arr(dst, u8, routelen);
|
||||
read_buffer(dst->routinginfo, src, routelen, &p);
|
||||
read_buffer(&dst->mac, src, HMAC_SIZE, &p);
|
||||
assert(p == srclen);
|
||||
|
||||
write_buffer(dst, compressed + compressedlen - HMAC_SIZE, HMAC_SIZE,
|
||||
&p);
|
||||
return dst;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,14 @@ struct onionpacket {
|
|||
u8 routinginfo[ROUTING_INFO_SIZE];
|
||||
};
|
||||
|
||||
struct sphinx_compressed_onion {
|
||||
u8 version;
|
||||
struct pubkey ephemeralkey;
|
||||
u8 *routinginfo;
|
||||
u8 mac[HMAC_SIZE];
|
||||
};
|
||||
|
||||
|
||||
enum route_next_case {
|
||||
ONION_END = 0,
|
||||
ONION_FORWARD = 1,
|
||||
|
@ -250,8 +258,9 @@ bool sphinx_path_set_rendezvous(struct sphinx_path *sp,
|
|||
* Given a compressed onion expand it by re-generating the prefiller and
|
||||
* inserting it in the appropriate place.
|
||||
*/
|
||||
u8 *sphinx_decompress(const tal_t *ctx, const u8 *compressed,
|
||||
struct secret *shared_secret);
|
||||
struct onionpacket *sphinx_decompress(const tal_t *ctx,
|
||||
const struct sphinx_compressed_onion *src,
|
||||
const struct secret *shared_secret);
|
||||
|
||||
/**
|
||||
* Use ECDH to generate a shared secret from a privkey and a pubkey.
|
||||
|
@ -264,6 +273,20 @@ bool sphinx_create_shared_secret(struct secret *privkey,
|
|||
const struct pubkey *pubkey,
|
||||
const struct secret *secret);
|
||||
|
||||
|
||||
/**
|
||||
* Given a compressible onionpacket, return the compressed version.
|
||||
*/
|
||||
struct sphinx_compressed_onion *
|
||||
sphinx_compress(const tal_t *ctx, const struct onionpacket *packet,
|
||||
const struct sphinx_path *path);
|
||||
|
||||
u8 *sphinx_compressed_onion_serialize(
|
||||
const tal_t *ctx, const struct sphinx_compressed_onion *onion);
|
||||
|
||||
struct sphinx_compressed_onion *
|
||||
sphinx_compressed_onion_deserialize(const tal_t *ctx, const u8 *src);
|
||||
|
||||
#if DEVELOPER
|
||||
/* Override to force us to reject valid onion packets */
|
||||
extern bool dev_fail_process_onionpacket;
|
||||
|
|
|
@ -294,9 +294,11 @@ static void decompress(char *hexprivkey, char *hexonion)
|
|||
{
|
||||
struct privkey rendezvous_key;
|
||||
size_t onionlen = hex_data_size(strlen(hexonion));
|
||||
u8 *compressed, *decompressed;
|
||||
u8 *compressed;
|
||||
struct pubkey ephkey;
|
||||
struct secret shared_secret;
|
||||
struct onionpacket *onion;
|
||||
struct sphinx_compressed_onion *tinyonion;
|
||||
|
||||
if (!hex_decode(hexprivkey, strlen(hexprivkey), &rendezvous_key, sizeof(rendezvous_key)))
|
||||
errx(1, "Invalid private key hex '%s'", hexprivkey);
|
||||
|
|
Loading…
Add table
Reference in a new issue