sphinx

package module
v4.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 19, 2024 License: MIT Imports: 18 Imported by: 6

README

lightning-onion

Build Status MIT License

Overview

This repository houses an implementation of the Lightning Network's onion routing protocol, adapted to the Decred network. The Lightning Network uses onion routing to securely, and privately route HTLC's (Hash-Time-Locked-Contracts, basically a conditional payment) within the network. (A full specification of the protocol can be found amongst the lighting-rfc repository, specifically within BOLT#04.

The Lightning Network is composed of a series of "payment channels" which are essentially tubes of money whose balances can instantaneous be reallocated between two participants. By linking these payment channels in a pair-wise manner, a network of connect payment channels are created.

Within the Lightning Network, source-routing is utilized in order to give nodes full control over the route their payment follows within the network. This level of control is highly desirable as with it, senders are able to fully specify: the total number of hops in their routes, the total cumulative fee they'll pay to send the payment, and finally the total worst-case time-lock period enforced by the conditional payment contract.

In line with Bitcoin's spirit of decentralization and censorship resistance, we employ an onion routing scheme within the Lightning protocol to prevent the ability of participants on the network to easily censor payments, as the participants are not aware of the final destination of any given payment. Additionally, by encoding payment routes within a mix-net like packet, we are able to achieve the following security and privacy features:

  • Participants in a route don't know their exact position within the route
  • Participants within a route don't know the source of the payment, nor the ultimate destination of the payment
  • Participants within a route aren't aware exactly how many other participants were involved in the payment route
  • Each new payment route is computationally indistinguishable from any other payment route

Our current onion routing protocol utilizes a message format derived from Sphinx. In order to cater Sphinx's mix-format to our specification application, we've made the following modifications:

  • We've added a MAC over the entire mix-header as we have no use for SURB's (single-use-reply-blocks) in our protocol.
  • Additionally, the end-to-end payload to the destination has been removed in order to cut down on the packet-size, and also as we don't currently have a use for a large message from payment sender to recipient.
  • We've dropped usage of LIONESS (as we don't need SURB's), and instead utilize chacha20 uniformly throughout as a stream cipher.
  • Finally, the mix-header has been extended with a per-hop-payload which provides each hops with exact instructions as to how and where to forward the payment. This includes the amount to forward, the destination chain, and the time-lock value to attach to the outgoing HTLC.

For further information see these resources:

In the near future, this repository will be extended to also includes a application specific version of HORNET.

Documentation

Index

Constants

View Source
const (
	// addressSize is the length of the serialized address used to uniquely
	// identify the next hop to forward the onion to. BOLT 04 defines this
	// as 8 byte channel_id.
	AddressSize = 8

	// RealmByteSize is the number of bytes that the realm byte occupies.
	RealmByteSize = 1

	// AmtForwardSize is the number of bytes that the amount to forward
	// occupies.
	AmtForwardSize = 8

	// OutgoingCLTVSize is the number of bytes that the outgoing CLTV value
	// occupies.
	OutgoingCLTVSize = 4

	// NumPaddingBytes is the number of padding bytes in the hopData. These
	// bytes are currently unused within the protocol, and are reserved for
	// future use. However, if a hop contains extra data, then we'll
	// utilize this space to pack in the unrolled bytes.
	NumPaddingBytes = 12

	// LegacyHopDataSize is the fixed size of hop_data. BOLT 04 currently
	// specifies this to be 1 byte realm, 8 byte channel_id, 8 byte amount
	// to forward, 4 byte outgoing CLTV value, 12 bytes padding and 32 bytes
	// HMAC for a total of 65 bytes per hop.
	LegacyHopDataSize = (RealmByteSize + AddressSize + AmtForwardSize +
		OutgoingCLTVSize + NumPaddingBytes + HMACSize)

	// MaxPayloadSize is the maximum size a payload for a single hop can be.
	// This is the worst case scenario of a single hop, consuming all
	// available space. We need to know this in order to generate a
	// sufficiently long stream of pseudo-random bytes when
	// encrypting/decrypting the payload.
	MaxPayloadSize = routingInfoSize
)
View Source
const (
	// ExitNode indicates that the node which processed the Sphinx packet
	// is the destination hop in the route.
	ExitNode = iota

	// MoreHops indicates that there are additional hops left within the
	// route. Therefore the caller should forward the packet to the node
	// denoted as the "NextHop".
	MoreHops

	// Failure indicates that a failure occurred during packet processing.
	Failure
)
View Source
const (
	// HMACSize is the length of the HMACs used to verify the integrity of
	// the onion. Any value lower than 32 will truncate the HMAC both
	// during onion creation as well as during the verification.
	HMACSize = 32
)
View Source
const (
	// HashPrefixSize is the size in bytes of the keys we will be storing
	// in the ReplayLog. It represents the first 20 bytes of a truncated
	// sha-256 hash of a secret generated by ECDH.
	HashPrefixSize = 20
)
View Source
const NumMaxHops = 27

NumMaxHops is the maximum path length. There is a maximum of 1300 bytes in the routing info block. Legacy hop payloads are always 65 bytes, while tlv payloads are at least 47 bytes (tlvlen 1, amt 2, timelock 2, nextchan 10, hmac 32) for the intermediate hops and 37 bytes (tlvlen 1, amt 2, timelock 2, hmac 32) for the exit hop. The maximum path length can therefore only be reached by using tlv payloads only. With that, the maximum number of intermediate hops is: Floor((1300 - 37) / 47) = 26. Including the exit hop, the maximum path length is 27 hops.

Variables

View Source
var (
	// ErrReplayedPacket is an error returned when a packet is rejected
	// during processing due to being an attempted replay or probing
	// attempt.
	ErrReplayedPacket = fmt.Errorf("sphinx packet replay attempted")

	// ErrInvalidOnionVersion is returned during decoding of the onion
	// packet, when the received packet has an unknown version byte.
	ErrInvalidOnionVersion = fmt.Errorf("invalid onion packet version")

	// ErrInvalidOnionHMAC is returned during onion parsing process, when received
	// mac does not corresponds to the generated one.
	ErrInvalidOnionHMAC = fmt.Errorf("invalid mismatched mac")

	// ErrInvalidOnionKey is returned during onion parsing process, when
	// onion key is invalid.
	ErrInvalidOnionKey = fmt.Errorf("invalid onion key: pubkey isn't on " +
		"secp256k1 curve")

	// ErrLogEntryNotFound is an error returned when a packet lookup in a replay
	// log fails because it is missing.
	ErrLogEntryNotFound = fmt.Errorf("sphinx packet is not in log")
)
View Source
var ErrAlreadyCommitted = errors.New("cannot add to batch after committing")

ErrAlreadyCommitted signals that an entry could not be added to the batch because it has already been persisted.

View Source
var (
	ErrMaxRoutingInfoSizeExceeded = fmt.Errorf(
		"max routing info size of %v bytes exceeded", routingInfoSize)
)
View Source
var ErrVarIntNotCanonical = errors.New("decoded varint is not canonical")

ErrVarIntNotCanonical signals that the decoded varint was not minimally encoded.

Functions

func BlankPacketFiller

func BlankPacketFiller(_ *secp256k1.PrivateKey, _ *[routingInfoSize]byte) error

BlankPacketFiller is a packet filler that doesn't attempt to fill out the packet at all. It should ONLY be used for generating test vectors or other instances that required deterministic packet generation.

func DeterministicPacketFiller

func DeterministicPacketFiller(sessionKey *secp256k1.PrivateKey,
	mixHeader *[routingInfoSize]byte) error

DeterministicPacketFiller is a packet filler that generates a deterministic set of filler bytes by using chacha20 with a key derived from the session key.

func RandPacketFiller

func RandPacketFiller(_ *secp256k1.PrivateKey, mixHeader *[routingInfoSize]byte) error

RandPacketFiller is a packet filler that reads a set of random bytes from a CSPRNG.

func ReadVarInt

func ReadVarInt(r io.Reader, buf *[8]byte) (uint64, error)

ReadVarInt reads a variable length integer from r and returns it as a uint64.

func UseLogger

func UseLogger(logger slog.Logger)

UseLogger uses a specified Logger to output package logging info. This should be used in preference to SetLogWriter if the caller is also using slog.

func WriteVarInt

func WriteVarInt(w io.Writer, val uint64, buf *[8]byte) error

WriteVarInt serializes val to w using a variable number of bytes depending on its value.

Types

type Batch

type Batch struct {
	// IsCommitted denotes whether or not this batch has been successfully
	// written to disk.
	IsCommitted bool

	// ID is a unique, caller chosen identifier for this batch.
	ID []byte

	// ReplaySet contains the sequence numbers of all entries that were
	// detected as replays. The set is finalized upon writing the batch to
	// disk, and merges replays detected by the replay cache and on-disk
	// replay log.
	ReplaySet *ReplaySet
	// contains filtered or unexported fields
}

Batch is an object used to incrementally construct a set of entries to add to the replay log. After construction is completed, it can be added to the log using the PutBatch method.

func NewBatch

func NewBatch(id []byte) *Batch

NewBatch initializes an object for constructing a set of entries to atomically add to a replay log. Batches are identified by byte slice, which allows the caller to safely process the same batch twice and get an idempotent result.

func (*Batch) ForEach

func (b *Batch) ForEach(fn func(seqNum uint16, hashPrefix *HashPrefix, cltv uint32) error) error

ForEach iterates through each entry in the batch and calls the provided function with the sequence number and entry contents as arguments.

func (*Batch) Put

func (b *Batch) Put(seqNum uint16, hashPrefix *HashPrefix, cltv uint32) error

Put inserts a hash-prefix/CLTV pair into the current batch. This method only returns an error in the event that the batch was already committed to disk. Decisions regarding whether or not a particular sequence number is a replay is ultimately reported via the batch's ReplaySet after committing to disk.

type Circuit

type Circuit struct {
	// SessionKey is the key which have been used during generation of the
	// shared secrets.
	SessionKey *secp256k1.PrivateKey

	// PaymentPath is the pub keys of the nodes in the payment path.
	PaymentPath []*secp256k1.PublicKey
}

Circuit is used encapsulate the data which is needed for data deobfuscation.

func (*Circuit) Decode

func (c *Circuit) Decode(r io.Reader) error

Decode initializes the circuit from the byte stream.

func (*Circuit) Encode

func (c *Circuit) Encode(w io.Writer) error

Encode writes converted circuit in the byte stream.

type DecryptedError

type DecryptedError struct {
	// Sender is the node that sent the error. Note that a node may occur in
	// the path multiple times. If that is the case, the sender pubkey does
	// not tell the caller on which visit the error occurred.
	Sender *secp256k1.PublicKey

	// SenderIdx is the position of the error sending node in the path.
	// Index zero is the self node. SenderIdx allows to distinguish between
	// errors from nodes that occur in the path multiple times.
	SenderIdx int

	// Message is the decrypted error message.
	Message []byte
}

DecryptedError contains the decrypted error message and its sender.

type Hash256

type Hash256 [sha256.Size]byte

Hash256 is a statically sized, 32-byte array, typically containing the output of a SHA256 hash.

type HashPrefix

type HashPrefix [HashPrefixSize]byte

HashPrefix is a statically size, 20-byte array containing the prefix of a Hash256, and is used to detect duplicate sphinx packets.

type HopData

type HopData struct {
	// Realm denotes the "real" of target chain of the next hop. For
	// bitcoin, this value will be 0x00.
	Realm [RealmByteSize]byte

	// NextAddress is the address of the next hop that this packet should
	// be forward to.
	NextAddress [AddressSize]byte

	// ForwardAmount is the HTLC amount that the next hop should forward.
	// This value should take into account the fee require by this
	// particular hop, and the cumulative fee for the entire route.
	ForwardAmount uint64

	// OutgoingCltv is the value of the outgoing absolute time-lock that
	// should be included in the HTLC forwarded.
	OutgoingCltv uint32

	// ExtraBytes is the set of unused bytes within the onion payload. This
	// extra set of bytes can be utilized by higher level applications to
	// package additional data within the per-hop payload, or signal that a
	// portion of the remaining set of hops are to be consumed as Extra
	// Onion Blobs.
	//
	// TODO(roasbeef): rename to padding bytes?
	ExtraBytes [NumPaddingBytes]byte
}

HopData is the information destined for individual hops. It is a fixed size 64 bytes, prefixed with a 1 byte realm that indicates how to interpret it. For now we simply assume it's the bitcoin realm (0x00) and hence the format is fixed. The last 32 bytes are always the HMAC to be passed to the next hop, or zero if this is the packet is not to be forwarded, since this is the last hop.

func (*HopData) Decode

func (hd *HopData) Decode(r io.Reader) error

Decodes populates the target HopData with the contents of a serialized HopData packed into the passed io.Reader.

func (*HopData) Encode

func (hd *HopData) Encode(w io.Writer) error

Encode writes the serialized version of the target HopData into the passed io.Writer.

type HopPayload

type HopPayload struct {
	// Type is the type of the payload.
	Type PayloadType

	// Payload is the raw bytes of the per-hop payload for this hop.
	// Depending on the realm, this pay be the regular legacy hop data, or
	// a set of opaque blobs to be parsed by higher layers.
	Payload []byte

	// HMAC is an HMAC computed over the entire per-hop payload that also
	// includes the higher-level (optional) associated data bytes.
	HMAC [HMACSize]byte
}

HopPayload is a slice of bytes and associated payload-type that are destined for a specific hop in the PaymentPath. The payload itself is treated as an opaque data field by the onion router. The included Type field informs the serialization/deserialziation of the raw payload.

func NewHopPayload

func NewHopPayload(hopData *HopData, eob []byte) (HopPayload, error)

NewHopPayload creates a new hop payload given an optional set of forwarding instructions for a hop, and a set of optional opaque extra onion bytes to drop off at the target hop. If both values are not specified, then an error is returned.

func (*HopPayload) Decode

func (hp *HopPayload) Decode(r io.Reader) error

Decode unpacks an encoded HopPayload from the passed reader into the target HopPayload.

func (*HopPayload) Encode

func (hp *HopPayload) Encode(w io.Writer) error

Encode encodes the hop payload into the passed writer.

func (*HopPayload) HopData

func (hp *HopPayload) HopData() (*HopData, error)

HopData attempts to extract a set of forwarding instructions from the target HopPayload. If the realm isn't what we expect, then an error is returned. This method also returns the left over EOB that remain after the hop data has been parsed. Callers may want to map this blob into something more concrete.

func (*HopPayload) NumBytes

func (hp *HopPayload) NumBytes() int

NumBytes returns the number of bytes it will take to serialize the full payload. Depending on the payload type, this may include some additional signalling bytes.

type MemoryReplayLog

type MemoryReplayLog struct {
	// contains filtered or unexported fields
}

MemoryReplayLog is a simple ReplayLog implementation that stores all added sphinx packets and processed batches in memory with no persistence.

This is designed for use just in testing.

func NewMemoryReplayLog

func NewMemoryReplayLog() *MemoryReplayLog

NewMemoryReplayLog constructs a new MemoryReplayLog.

func (*MemoryReplayLog) Delete

func (rl *MemoryReplayLog) Delete(hash *HashPrefix) error

Delete deletes an entry from the log given its hash prefix.

func (*MemoryReplayLog) Get

func (rl *MemoryReplayLog) Get(hash *HashPrefix) (uint32, error)

Get retrieves an entry from the log given its hash prefix. It returns the value stored and an error if one occurs. It returns ErrLogEntryNotFound if the entry is not in the log.

func (*MemoryReplayLog) Put

func (rl *MemoryReplayLog) Put(hash *HashPrefix, cltv uint32) error

Put stores an entry into the log given its hash prefix and an accompanying purposefully general type. It returns ErrReplayedPacket if the provided hash prefix already exists in the log.

func (*MemoryReplayLog) PutBatch

func (rl *MemoryReplayLog) PutBatch(batch *Batch) (*ReplaySet, error)

PutBatch stores a batch of sphinx packets into the log given their hash prefixes and accompanying values. Returns the set of entries in the batch that are replays and an error if one occurs.

func (*MemoryReplayLog) Start

func (rl *MemoryReplayLog) Start() error

Start initializes the log and must be called before any other methods.

func (*MemoryReplayLog) Stop

func (rl *MemoryReplayLog) Stop() error

Stop wipes the state of the log.

type OnionErrorDecrypter

type OnionErrorDecrypter struct {
	// contains filtered or unexported fields
}

OnionErrorDecrypter is a struct that's used to decrypt onion errors in response to failed HTLC routing attempts according to BOLT#4.

func NewOnionErrorDecrypter

func NewOnionErrorDecrypter(circuit *Circuit) *OnionErrorDecrypter

NewOnionErrorDecrypter creates new instance of onion decrypter.

func (*OnionErrorDecrypter) DecryptError

func (o *OnionErrorDecrypter) DecryptError(encryptedData []byte) (
	*DecryptedError, error)

DecryptError attempts to decrypt the passed encrypted error response. The onion failure is encrypted in backward manner, starting from the node where error have occurred. As a result, in order to decrypt the error we need get all shared secret and apply decryption in the reverse order. A structure is returned that contains the decrypted error message and information on the sender.

type OnionErrorEncrypter

type OnionErrorEncrypter struct {
	// contains filtered or unexported fields
}

OnionErrorEncrypter is a struct that's used to implement onion error encryption as defined within BOLT0004.

func NewOnionErrorEncrypter

func NewOnionErrorEncrypter(router *Router,
	ephemeralKey *secp256k1.PublicKey) (*OnionErrorEncrypter, error)

NewOnionErrorEncrypter creates new instance of the onion encrypter backed by the passed router, with encryption to be doing using the passed ephemeralKey.

func (*OnionErrorEncrypter) Decode

func (o *OnionErrorEncrypter) Decode(r io.Reader) error

Decode restores the encrypter's share secret from the provided io.Reader.

func (*OnionErrorEncrypter) Encode

func (o *OnionErrorEncrypter) Encode(w io.Writer) error

Encode writes the encrypter's shared secret to the provided io.Writer.

func (*OnionErrorEncrypter) EncryptError

func (o *OnionErrorEncrypter) EncryptError(initial bool, data []byte) []byte

EncryptError is used to make data obfuscation using the generated shared secret.

In context of Lightning Network is either used by the nodes in order to make initial obfuscation with the creation of the hmac or by the forwarding nodes for backward failure obfuscation of the onion failure blob. By obfuscating the onion failure on every node in the path we are adding additional step of the security and barrier for malware nodes to retrieve valuable information. The reason for using onion obfuscation is to not give away to the nodes in the payment path the information about the exact failure and its origin.

type OnionHop

type OnionHop struct {
	// NodePub is the target node for this hop. The payload will enter this
	// hop, it'll decrypt the routing information, and hand off the
	// internal packet to the next hop.
	NodePub secp256k1.PublicKey

	// HopPayload is the opaque payload provided to this node. If the
	// HopData above is specified, then it'll be packed into this payload.
	HopPayload HopPayload
}

OnionHop represents an abstract hop (a link between two nodes) within the Lightning Network. A hop is composed of the incoming node (able to decrypt the encrypted routing information), and the routing information itself. Optionally, the crafter of a route can indicate that additional data aside from the routing information is be delivered, which will manifest as additional hops to pack the data.

func (OnionHop) IsEmpty

func (o OnionHop) IsEmpty() bool

IsEmpty returns true if the hop isn't populated.

type OnionPacket

type OnionPacket struct {
	// Version denotes the version of this onion packet. The version
	// indicates how a receiver of the packet should interpret the bytes
	// following this version byte. Currently, a version of 0x00 is the
	// only defined version type.
	Version byte

	// EphemeralKey is the public key that each hop will used in
	// combination with the private key in an ECDH to derive the shared
	// secret used to check the HMAC on the packet and also decrypted the
	// routing information.
	EphemeralKey *secp256k1.PublicKey

	// RoutingInfo is the full routing information for this onion packet.
	// This encodes all the forwarding instructions for this current hop
	// and all the hops in the route.
	RoutingInfo [routingInfoSize]byte

	// HeaderMAC is an HMAC computed with the shared secret of the routing
	// data and the associated data for this route. Including the
	// associated data lets each hop authenticate higher-level data that is
	// critical for the forwarding of this HTLC.
	HeaderMAC [HMACSize]byte
}

OnionPacket is the onion wrapped hop-to-hop routing information necessary to propagate a message through the mix-net without intermediate nodes having knowledge of their position within the route, the source, the destination, and finally the identities of the past/future nodes in the route. At each hop the ephemeral key is used by the node to perform ECDH between itself and the source node. This derived secret key is used to check the MAC of the entire mix header, decrypt the next set of routing information, and re-randomize the ephemeral key for the next node in the path. This per-hop re-randomization allows us to only propagate a single group element through the onion route.

func NewOnionPacket

func NewOnionPacket(paymentPath *PaymentPath, sessionKey *secp256k1.PrivateKey,
	assocData []byte, pktFiller PacketFiller) (*OnionPacket, error)

NewOnionPacket creates a new onion packet which is capable of obliviously routing a message through the mix-net path outline by 'paymentPath'.

func (*OnionPacket) Decode

func (f *OnionPacket) Decode(r io.Reader) error

Decode fully populates the target ForwardingMessage from the raw bytes encoded within the io.Reader. In the case of any decoding errors, an error will be returned. If the method success, then the new OnionPacket is ready to be processed by an instance of SphinxNode.

func (*OnionPacket) Encode

func (f *OnionPacket) Encode(w io.Writer) error

Encode serializes the raw bytes of the onion packet into the passed io.Writer. The form encoded within the passed io.Writer is suitable for either storing on disk, or sending over the network.

type PacketFiller

type PacketFiller func(*secp256k1.PrivateKey, *[routingInfoSize]byte) error

PacketFiller is a function type to be specified by the caller to provide a stream of random bytes derived from a CSPRNG to fill out the starting packet in order to ensure we don't leak information on the true route length to the receiver. The packet filler may also use the session key to generate a set of filler bytes if it wishes to be deterministic.

type PayloadType

type PayloadType uint8

PayloadType denotes the type of the payload included in the onion packet. Serialization of a raw HopPayload will depend on the payload type, as some include a varint length prefix, while others just encode the raw payload.

const (
	// PayloadLegacy is the legacy payload type. It includes a fixed 32
	// bytes, 12 of which are padding, and uses a "zero length" (the old
	// realm) prefix.
	PayloadLegacy PayloadType = iota

	// PayloadTLV is the new modern TLV based format. This payload includes
	// a set of opaque bytes with a varint length prefix. The varint used
	// is the same CompactInt as used in the Bitcoin protocol.
	PayloadTLV
)

type PaymentPath

type PaymentPath [NumMaxHops]OnionHop

PaymentPath represents a series of hops within the Lightning Network starting at a sender and terminating at a receiver. Each hop contains a set of mandatory data which contains forwarding instructions for that hop. Additionally, we can also transmit additional data to each hop by utilizing the un-used hops (see TrueRouteLength()) to pack in additional data. In order to do this, we encrypt the several hops with the same node public key, and unroll the extra data into the space used for route forwarding information.

func (*PaymentPath) NodeKeys

func (p *PaymentPath) NodeKeys() []*secp256k1.PublicKey

NodeKeys returns a slice pointing to node keys that this route comprises of. The size of the returned slice will be TrueRouteLength().

func (*PaymentPath) TotalPayloadSize

func (p *PaymentPath) TotalPayloadSize() int

TotalPayloadSize returns the sum of the size of each payload in the "true" route.

func (*PaymentPath) TrueRouteLength

func (p *PaymentPath) TrueRouteLength() int

TrueRouteLength returns the "true" length of the PaymentPath. The max payment path is NumMaxHops size, but in practice routes are much smaller. This method will return the number of actual hops (nodes) involved in this route. For references, a direct path has a length of 1, path through an intermediate node has a length of 2 (3 nodes involved).

type PrivKeyECDH

type PrivKeyECDH struct {
	// PrivKey is the private key that is used for the ECDH operation.
	PrivKey *secp256k1.PrivateKey
}

PrivKeyECDH is an implementation of the SingleKeyECDH in which we do have the full private key. This can be used to wrap a temporary key to conform to the SingleKeyECDH interface.

func (*PrivKeyECDH) ECDH

func (p *PrivKeyECDH) ECDH(pub *secp256k1.PublicKey) ([32]byte, error)

ECDH performs a scalar multiplication (ECDH-like operation) between the abstracted private key and a remote public key. The output returned will be the sha256 of the resulting shared point serialized in compressed format. If k is our private key, and P is the public key, we perform the following operation:

sx := k*P
s := sha256(sx.SerializeCompressed())

NOTE: This is part of the SingleKeyECDH interface.

func (*PrivKeyECDH) PubKey

func (p *PrivKeyECDH) PubKey() *secp256k1.PublicKey

PubKey returns the public key of the private key that is abstracted away by the interface.

NOTE: This is part of the SingleKeyECDH interface.

type ProcessCode

type ProcessCode int

ProcessCode is an enum-like type which describes to the high-level package user which action should be taken after processing a Sphinx packet.

func (ProcessCode) String

func (p ProcessCode) String() string

String returns a human readable string for each of the ProcessCodes.

type ProcessedPacket

type ProcessedPacket struct {
	// Action represents the action the caller should take after processing
	// the packet.
	Action ProcessCode

	// ForwardingInstructions is the per-hop payload recovered from the
	// initial encrypted onion packet. It details how the packet should be
	// forwarded and also includes information that allows the processor of
	// the packet to authenticate the information passed within the HTLC.
	//
	// NOTE: This field will only be populated iff the above Action is
	// MoreHops.
	ForwardingInstructions *HopData

	// Payload is the raw payload as extracted from the packet. If the
	// ForwardingInstructions field above is nil, then this is a modern TLV
	// payload. As a result, the caller should parse the contents to obtain
	// the new set of forwarding instructions.
	Payload HopPayload

	// NextPacket is the onion packet that should be forwarded to the next
	// hop as denoted by the ForwardingInstructions field.
	//
	// NOTE: This field will only be populated iff the above Action is
	// MoreHops.
	NextPacket *OnionPacket
}

ProcessedPacket encapsulates the resulting state generated after processing an OnionPacket. A processed packet communicates to the caller what action should be taken after processing.

type ReplayLog

type ReplayLog interface {
	// Start starts up the log. It returns an error if one occurs.
	Start() error

	// Stop safely stops the log. It returns an error if one occurs.
	Stop() error

	// Get retrieves an entry from the log given its hash prefix. It returns the
	// value stored and an error if one occurs. It returns ErrLogEntryNotFound
	// if the entry is not in the log.
	Get(*HashPrefix) (uint32, error)

	// Put stores an entry into the log given its hash prefix and an
	// accompanying purposefully general type. It returns ErrReplayedPacket if
	// the provided hash prefix already exists in the log.
	Put(*HashPrefix, uint32) error

	// Delete deletes an entry from the log given its hash prefix.
	Delete(*HashPrefix) error

	// PutBatch stores a batch of sphinx packets into the log given their hash
	// prefixes and accompanying values. Returns the set of entries in the batch
	// that are replays and an error if one occurs.
	PutBatch(*Batch) (*ReplaySet, error)
}

ReplayLog is an interface that defines a log of incoming sphinx packets, enabling strong replay protection. The interface is general to allow implementations near-complete autonomy. All methods must be safe for concurrent access.

type ReplaySet

type ReplaySet struct {
	// contains filtered or unexported fields
}

ReplaySet is a data structure used to efficiently record the occurrence of replays, identified by sequence number, when processing a Batch. Its primary functionality includes set construction, membership queries, and merging of replay sets.

func NewReplaySet

func NewReplaySet() *ReplaySet

NewReplaySet initializes an empty replay set.

func (*ReplaySet) Add

func (rs *ReplaySet) Add(idx uint16)

Add inserts the provided index into the replay set.

func (*ReplaySet) Contains

func (rs *ReplaySet) Contains(idx uint16) bool

Contains queries the contents of the replay set for membership of a particular index.

func (*ReplaySet) Decode

func (rs *ReplaySet) Decode(r io.Reader) error

Decode reconstructs a replay set given a io.Reader. The byte slice is assumed to be even in length, otherwise resulting in failure.

func (*ReplaySet) Encode

func (rs *ReplaySet) Encode(w io.Writer) error

Encode serializes the replay set into an io.Writer suitable for storage. The replay set can be recovered using Decode.

func (*ReplaySet) Merge

func (rs *ReplaySet) Merge(rs2 *ReplaySet)

Merge adds the contents of the provided replay set to the receiver's set.

func (*ReplaySet) Size

func (rs *ReplaySet) Size() int

Size returns the number of elements in the replay set.

type Router

type Router struct {
	// contains filtered or unexported fields
}

Router is an onion router within the Sphinx network. The router is capable of processing incoming Sphinx onion packets thereby "peeling" a layer off the onion encryption which the packet is wrapped with.

func NewRouter

func NewRouter(nodeKey SingleKeyECDH, net dcrutil.AddressParams, log ReplayLog) *Router

NewRouter creates a new instance of a Sphinx onion Router given the node's currently advertised onion private key, and the target Bitcoin network.

func (*Router) BeginTxn

func (r *Router) BeginTxn(id []byte, nels int) *Tx

BeginTxn creates a new transaction that can later be committed back to the sphinx router's replay log.

NOTE: The nels parameter should represent the maximum number of that could be added to the batch, using sequence numbers that match or exceed this value could result in an out-of-bounds panic.

func (*Router) ProcessOnionPacket

func (r *Router) ProcessOnionPacket(onionPkt *OnionPacket,
	assocData []byte, incomingCltv uint32) (*ProcessedPacket, error)

ProcessOnionPacket processes an incoming onion packet which has been forward to the target Sphinx router. If the encoded ephemeral key isn't on the target Elliptic Curve, then the packet is rejected. Similarly, if the derived shared secret has been seen before the packet is rejected. Finally if the MAC doesn't check the packet is again rejected.

In the case of a successful packet processing, and ProcessedPacket struct is returned which houses the newly parsed packet, along with instructions on what to do next.

func (*Router) ReconstructOnionPacket

func (r *Router) ReconstructOnionPacket(onionPkt *OnionPacket,
	assocData []byte) (*ProcessedPacket, error)

ReconstructOnionPacket rederives the subsequent onion packet.

NOTE: This method does not do any sort of replay protection, and should only be used to reconstruct packets that were successfully processed previously.

func (*Router) Start

func (r *Router) Start() error

Start starts / opens the ReplayLog's channeldb and its accompanying garbage collector goroutine.

func (*Router) Stop

func (r *Router) Stop()

Stop stops / closes the ReplayLog's channeldb and its accompanying garbage collector goroutine.

type SingleKeyECDH

type SingleKeyECDH interface {
	// PubKey returns the public key of the private key that is abstracted
	// away by the interface.
	PubKey() *secp256k1.PublicKey

	// ECDH performs a scalar multiplication (ECDH-like operation) between
	// the abstracted private key and a remote public key. The output
	// returned will be the sha256 of the resulting shared point serialized
	// in compressed format.
	ECDH(pubKey *secp256k1.PublicKey) ([32]byte, error)
}

SingleKeyECDH is an abstraction interface that hides the implementation of an ECDH operation against a specific private key. We use this abstraction for the long term keys which we eventually want to be able to keep in a hardware wallet or HSM.

type Tx

type Tx struct {
	sync.Mutex
	// contains filtered or unexported fields
}

Tx is a transaction consisting of a number of sphinx packets to be atomically written to the replay log. This structure helps to coordinate construction of the underlying Batch object, and to ensure that the result of the processing is idempotent.

func (*Tx) Commit

func (t *Tx) Commit() ([]ProcessedPacket, *ReplaySet, error)

Commit writes this transaction's batch of sphinx packets to the replay log, performing a final check against the log for replays.

func (*Tx) ProcessOnionPacket

func (t *Tx) ProcessOnionPacket(seqNum uint16, onionPkt *OnionPacket,
	assocData []byte, incomingCltv uint32) error

ProcessOnionPacket processes an incoming onion packet which has been forward to the target Sphinx router. If the encoded ephemeral key isn't on the target Elliptic Curve, then the packet is rejected. Similarly, if the derived shared secret has been seen before the packet is rejected. Finally if the MAC doesn't check the packet is again rejected.

In the case of a successful packet processing, and ProcessedPacket struct is returned which houses the newly parsed packet, along with instructions on what to do next.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL