|
|
|
#ifndef LIGHTNING_COMMON_SPHINX_H
|
|
|
|
#define LIGHTNING_COMMON_SPHINX_H
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include "bitcoin/privkey.h"
|
|
|
|
#include "bitcoin/pubkey.h"
|
|
|
|
|
|
|
|
#include <ccan/short_types/short_types.h>
|
|
|
|
#include <ccan/tal/tal.h>
|
|
|
|
#include <common/hmac.h>
|
|
|
|
#include <secp256k1.h>
|
|
|
|
#include <sodium/randombytes.h>
|
|
|
|
#include <wire/onion_wire.h>
|
|
|
|
|
|
|
|
struct node_id;
|
|
|
|
|
|
|
|
#define VERSION_SIZE 1
|
|
|
|
#define REALM_SIZE 1
|
|
|
|
#define HMAC_SIZE 32
|
|
|
|
#define PUBKEY_SIZE 33
|
|
|
|
#define FRAME_SIZE 65
|
|
|
|
#define ROUTING_INFO_SIZE 1300
|
|
|
|
#define TOTAL_PACKET_SIZE (VERSION_SIZE + PUBKEY_SIZE + HMAC_SIZE + ROUTING_INFO_SIZE)
|
|
|
|
|
|
|
|
struct onionpacket {
|
|
|
|
/* Cleartext information */
|
|
|
|
u8 version;
|
|
|
|
struct hmac hmac;
|
|
|
|
struct pubkey ephemeralkey;
|
|
|
|
|
|
|
|
/* Encrypted information */
|
|
|
|
u8 routinginfo[ROUTING_INFO_SIZE];
|
|
|
|
};
|
|
|
|
|
|
|
|
struct sphinx_compressed_onion {
|
|
|
|
u8 version;
|
|
|
|
struct pubkey ephemeralkey;
|
|
|
|
u8 *routinginfo;
|
|
|
|
struct hmac hmac;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
enum route_next_case {
|
|
|
|
ONION_END = 0,
|
|
|
|
ONION_FORWARD = 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A sphinx payment path.
|
|
|
|
*
|
|
|
|
* This struct defines a path a payment is taking through the Lightning
|
|
|
|
* Network, including the session_key used to generate secrets, the associated
|
|
|
|
* data that'll be included in the HMACs and the payloads at each hop in the
|
|
|
|
* path. The struct is opaque since it should not be modified externally. Use
|
|
|
|
* `sphinx_path_new` or `sphinx_path_new_with_key` (testing only) to create a
|
|
|
|
* new instance.
|
|
|
|
*/
|
|
|
|
struct sphinx_path;
|
|
|
|
|
|
|
|
/* BOLT #4:
|
|
|
|
*
|
|
|
|
* ## Legacy `hop_data` payload format
|
|
|
|
*
|
|
|
|
* The `hop_data` format is identified by a single `0x00`-byte length,
|
|
|
|
* for backward compatibility. Its payload is defined as:
|
|
|
|
*
|
|
|
|
* 1. type: `hop_data` (for `realm` 0)
|
|
|
|
* 2. data:
|
|
|
|
* * [`short_channel_id`:`short_channel_id`]
|
|
|
|
* * [`u64`:`amt_to_forward`]
|
|
|
|
* * [`u32`:`outgoing_cltv_value`]
|
|
|
|
* * [`12*byte`:`padding`]
|
|
|
|
*/
|
|
|
|
struct hop_data_legacy {
|
|
|
|
u8 realm;
|
|
|
|
struct short_channel_id channel_id;
|
|
|
|
struct amount_msat amt_forward;
|
|
|
|
u32 outgoing_cltv;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* All the necessary information to generate a valid onion for this hop on a
|
|
|
|
* sphinx path. The payload is preserialized in order since the onion
|
|
|
|
* generation is payload agnostic. */
|
|
|
|
struct sphinx_hop {
|
|
|
|
struct pubkey pubkey;
|
|
|
|
const u8 *raw_payload;
|
|
|
|
struct hmac hmac;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct route_step {
|
|
|
|
enum route_next_case nextcase;
|
|
|
|
struct onionpacket *next;
|
|
|
|
u8 *raw_payload;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* create_onionpacket - Create a new onionpacket that can be routed
|
|
|
|
* over a path of intermediate nodes.
|
|
|
|
*
|
|
|
|
* @ctx: tal context to allocate from
|
|
|
|
* @path: public keys of nodes along the path.
|
|
|
|
* @hoppayloads: payloads destined for individual hosts (limited to
|
|
|
|
* HOP_PAYLOAD_SIZE bytes)
|
|
|
|
* @num_hops: path length in nodes
|
|
|
|
* @sessionkey: 32 byte random session key to derive secrets from
|
|
|
|
* @assocdata: associated data to commit to in HMACs
|
|
|
|
* @assocdatalen: length of the assocdata
|
|
|
|
* @path_secrets: (out) shared secrets generated for the entire path
|
|
|
|
*/
|
|
|
|
struct onionpacket *create_onionpacket(
|
|
|
|
const tal_t * ctx,
|
|
|
|
struct sphinx_path *sp,
|
|
|
|
struct secret **path_secrets
|
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* onion_shared_secret - calculate ECDH shared secret between nodes.
|
|
|
|
*
|
|
|
|
* @secret: the shared secret
|
|
|
|
* @pubkey: the public key of the other node
|
|
|
|
* @privkey: the private key of this node (32 bytes long)
|
|
|
|
*/
|
|
|
|
bool onion_shared_secret(
|
|
|
|
struct secret *secret,
|
|
|
|
const struct onionpacket *packet,
|
|
|
|
const struct privkey *privkey);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* process_onionpacket - process an incoming packet by stripping one
|
|
|
|
* onion layer and return the packet for the next hop.
|
|
|
|
*
|
|
|
|
* @ctx: tal context to allocate from
|
|
|
|
* @packet: incoming packet being processed
|
|
|
|
* @shared_secret: the result of onion_shared_secret.
|
|
|
|
* @hoppayload: the per-hop payload destined for the processing node.
|
|
|
|
* @assocdata: associated data to commit to in HMACs
|
|
|
|
* @assocdatalen: length of the assocdata
|
|
|
|
* @has_realm: used for HTLCs, where first byte 0 is magical.
|
|
|
|
*/
|
|
|
|
struct route_step *process_onionpacket(
|
|
|
|
const tal_t * ctx,
|
|
|
|
const struct onionpacket *packet,
|
|
|
|
const struct secret *shared_secret,
|
|
|
|
const u8 *assocdata,
|
|
|
|
const size_t assocdatalen,
|
|
|
|
bool has_realm
|
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* serialize_onionpacket - Serialize an onionpacket to a buffer.
|
|
|
|
*
|
|
|
|
* @ctx: tal context to allocate from
|
|
|
|
* @packet: the packet to serialize
|
|
|
|
*/
|
|
|
|
u8 *serialize_onionpacket(
|
|
|
|
const tal_t *ctx,
|
|
|
|
const struct onionpacket *packet);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* parse_onionpacket - Parse an onionpacket from a buffer.
|
|
|
|
*
|
|
|
|
* @src: buffer to read the packet from
|
|
|
|
* @srclen: length of the @src (must be TOTAL_PACKET_SIZE)
|
|
|
|
* @dest: the destination into which we should parse the packet
|
|
|
|
*/
|
|
|
|
enum onion_wire parse_onionpacket(const u8 *src,
|
|
|
|
const size_t srclen,
|
|
|
|
struct onionpacket *dest);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* create_onionreply - Format a failure message so we can return it
|
|
|
|
*
|
|
|
|
* @ctx: tal context to allocate from
|
|
|
|
* @shared_secret: The shared secret used in the forward direction, used for the
|
|
|
|
* HMAC
|
|
|
|
* @failure_msg: message (must support tal_len)
|
|
|
|
*/
|
|
|
|
struct onionreply *create_onionreply(const tal_t *ctx,
|
|
|
|
const struct secret *shared_secret,
|
|
|
|
const u8 *failure_msg);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* wrap_onionreply - Add another encryption layer to the reply.
|
|
|
|
*
|
|
|
|
* @ctx: tal context to allocate from
|
|
|
|
* @shared_secret: the shared secret associated with the HTLC, used for the
|
|
|
|
* encryption.
|
|
|
|
* @reply: the reply to wrap
|
|
|
|
*/
|
|
|
|
struct onionreply *wrap_onionreply(const tal_t *ctx,
|
|
|
|
const struct secret *shared_secret,
|
|
|
|
const struct onionreply *reply);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* unwrap_onionreply - Remove layers, check integrity and parse reply
|
|
|
|
*
|
|
|
|
* @ctx: tal context to allocate from
|
|
|
|
* @shared_secrets: shared secrets from the forward path
|
|
|
|
* @numhops: path length and number of shared_secrets provided
|
|
|
|
* @reply: the incoming reply
|
|
|
|
* @origin_index: the index in the path where the reply came from (-1 if unknown)
|
|
|
|
*
|
|
|
|
* Reverses create_onionreply and wrap_onionreply.
|
|
|
|
*/
|
|
|
|
u8 *unwrap_onionreply(const tal_t *ctx,
|
|
|
|
const struct secret *shared_secrets,
|
|
|
|
const int numhops,
|
|
|
|
const struct onionreply *reply,
|
|
|
|
int *origin_index);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a new empty sphinx_path.
|
|
|
|
*
|
|
|
|
* The sphinx_path instance can then be decorated with other functions and
|
|
|
|
* passed to `create_onionpacket` to generate the packet.
|
|
|
|
*/
|
|
|
|
struct sphinx_path *sphinx_path_new(const tal_t *ctx,
|
|
|
|
const u8 *associated_data);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a new empty sphinx_path with a given `session_key`.
|
|
|
|
*
|
|
|
|
* This MUST NOT be used outside of tests and tools as it may leak the path
|
|
|
|
* details if the `session_key` is not randomly generated.
|
|
|
|
*/
|
|
|
|
struct sphinx_path *sphinx_path_new_with_key(const tal_t *ctx,
|
|
|
|
const u8 *associated_data,
|
|
|
|
const struct secret *session_key);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a payload hop to the path.
|
|
|
|
*/
|
|
|
|
void sphinx_add_hop(struct sphinx_path *path, const struct pubkey *pubkey,
|
|
|
|
const u8 *payload TAKES);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Compute the size of the serialized payloads.
|
|
|
|
*/
|
|
|
|
size_t sphinx_path_payloads_size(const struct sphinx_path *path);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the rendez-vous node_id and make the onion generated from the
|
|
|
|
* sphinx_path compressible. To unset pass in a NULL rendezvous_id.
|
|
|
|
*
|
|
|
|
* Returns false if there was an error converting from the node_id to a public
|
|
|
|
* key.
|
|
|
|
*/
|
|
|
|
bool sphinx_path_set_rendezvous(struct sphinx_path *sp,
|
|
|
|
const struct node_id *rendezvous_id);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Given a compressed onion expand it by re-generating the prefiller and
|
|
|
|
* inserting it in the appropriate place.
|
|
|
|
*/
|
|
|
|
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.
|
|
|
|
*
|
|
|
|
* Sphinx uses shared secrets derived from a private key and a public key
|
|
|
|
* using ECDH in a number of places. This is a simple wrapper around the
|
|
|
|
* secp256k1 functions, with our internal types.
|
|
|
|
*/
|
|
|
|
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;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif /* LIGHTNING_COMMON_SPHINX_H */
|