From f16691a98fcaf3ebd4e67822ae0f927d3018a9c7 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Tue, 6 Oct 2015 14:34:26 -0700 Subject: [PATCH] Initial brain dump of ln-hornet --- hornet.go | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 hornet.go diff --git a/hornet.go b/hornet.go new file mode 100644 index 000000000..8465c8776 --- /dev/null +++ b/hornet.go @@ -0,0 +1,167 @@ +package main + +import ( + "github.com/btcsuite/btcd/btcec" + "golang.org/x/crypto/ripemd160" +) + +// ========== Half Baked Idea to Allow Re-Routes via the Onion Route ========== +// So, it seems that using onion routing break re-routing by intermediate nodes +// (for w/e reason they deem neccessary). aj stumbled unto this realization in +// one of his latest mailing lists posts (I plan to post to the ML myself soon, +// but only after I've figured out all the quirks etc). ASIDE:: looks like Rusty is +// using zeroes as padding? HORNET uses random bytes in a way that still doesn't +// give away node position. +// +// I've thought of a way to allow intermdiate nodes to re-route, but it requires +// communicating with the source backwards on the onion route. Using HORNET, +// (during the set up phase) we can give each node in the hop the backwards +// AHDR (this allows them to route backwards to the source with a message) from +// their point of view. So basically, then have a partial onion (full onion is to destination). +// This would allow each of them to communicate back to the source since positions +// information isn't given away by the sphinx header, nor the data transmission header. +// This would let the intermediate nodes give recommendations of the route in a +// way. In the example: because a route is cheaper more capacity, non-responsive, +// rebalance route, etc. +// +// So, at first glance this looks to work. It avoids requiring the source to +// have a syncrhnous connection to *each* hop (which also makes the onio stuff +// pointless). +// ========================================================================== + +// ==== Half Baked Thought About Control/Message separation along route ===== +// Hop to hop data transmission implementation (negotiating changes to the commitment txns, adding htlc, etc) +// doesn't matter. Meaning, hop-to-hop the nodes can use w/e protos dictated +// by w/e protocol their running. Could even do some version exchange on first +// connect (yo I support v1, v2, vRusty (could have protocol bridges etc)). +// So the main standardization point is then on the fronts on control +// information within the onion routing: set up HTLC, re-route request, etc. +// ========================================================================= + +// TODO(roasbeef): Might need to change? due to the PRG* requirements? But +// yeh, once I add the LN specific stuff FSLength will change. Also doesn't +// 20 hops seem a bit excessive? 7? +const NumMaxHops = 20 +const FSLength = 48 + +// Hmm appears that they use k = 128 throughout the paper? + +// HMAC -> SHA-256 +// * or could use Poly1035: https://godoc.org/golang.org/x/crypto/poly1305 +// * but, the paper specs: {0, 1}^k x {0, 1}* -> {0, 1}^k +// * Poly1035 is actually: {0, 1}^k x {0, 1}* -> {0, 1}^(2/k) +// * Also with Poly, I guess the key is treated as a nonce, tagging two messages +// with the same key allows an attacker to forge message or something like that + +// Size of a forwarding segment is 32 bytes, the MAC is 16 bytes, so c = 48 bytes +// * NOTE: this doesn't include adding R to the forwarding segment, and w/e esle + +// Hmmm since each uses diff key, just use AES-CTR with blank nonce, given key, +// encrypt plaintext of all zeroes, this'll give us our len(plaintext) rand bytes. +// PRG0 -> {0, 1}^k -> {0, 1}^r(c+k) or {0, 1}^1280 (assuming 20 hops, like rusty, but, is that too large? maybe, idk) +// PRG1 -> {0, 1}^k -> {0, 1}^r(c+k) or {0, 1}^1280 (assuming 20 hops) +// PRG2 -> {0, 1}^k -> {0, 1}^rc or {0, 1}^960 (assuming 20 hops, c=48) +// * NOTE: in second version of paper (accepted to CCS'15), all the PRG*'s are like PRG2 +// * so makes it simpler + +// PRP -> AES? or +// * {0, 1}^k x {0, 1}^a -> {0, 1}^a + +// Do we need AEAD for the below? Or are is the per-hop MAC okay? +// ENC: AES-CTR or CHACHA20? + +// DEC: AES-CTR or CHACHA20? + +// h_op: G^* -> {0, 1}^k +// * op (elem of) {MAC, PRGO, PRG!, PRP, ENC, DEC} +// * key gen for the above essentially + +// paper doesn't really specify the format, gotta read the Sphinx paper for it. +// SphinxHeader... +type SphinxHeader struct { + // pretty sure this MAC will extend to the chdr also +} + +// SphinxPayload... +type SphinxPayload struct { +} + +// SphinxPacket... +type SphinxPacket struct { +} + +// GenerateSphinxHeader... +// Will create sphinx headers for the forward and backwards path, gen the shared +// sym keys via DH, and output the ephemeral key pair we used to gen the shared +// key with the nodes long-term DH key. +func GenerateSphinxHeader() (*SphinxHeader, *SphinxHeader, [][32]byte, []*btcec.PrivateKey) { + return nil, nil, nil, nil +} + +// RoutingSegment... +// NOTE: Length of routing segment in the paper is 8 bytes (enough for their +// imaginary network, I guess). But, looking like they'll be (20 + 33 bytes) +// 53 bytes. Or 52 if we use curve25519 +type RoutingSegment struct { + nextHop *btcec.PublicKey // NOTE: or, is this a LN addr? w/e that is? + // nextHop [32]byte + rCommitment [ripemd160.Size]byte + + // stuff perhaps? +} + +// ForwardingSegment.... +type ForwardingSegment struct { + // Here's hash(R), attempt to make an HTLC with the next hop. If + // successful, then pass along the onion so we can finish getting the + // payment circuit set up. + // TODO(roasbeef): Do we create HTLC's with the minimum amount + // possible? 1 satoshi or is it 1 mili-satoshi? + rs RoutingSegment + + // To defend against replay attacks. Intermediate nodes will drop the + // FS if it deems it's expired. + expiration uint64 + + // Key shared by intermediate node with the source, used to peel a layer + // off the onion for the next hop. + sharedSymmetricKey [32]byte // TODO(roasbeef): or, 16? + + mac [32]byte // TODO(roasbeef): or, 16? +} + +// AnonymousHeader... +type AnonymousHeader struct { + // Forwarding info for the current hop. When serialized, it'll be + // encrypted with SV, the secret key for this node known to no-one but + // the node. It also contains a secret key shared with this node and the + // source, so it can peel off a layer of the onion for the next hop. + FS ForwardingSegment +} + +// CommonHeader... +type CommonHeader struct { + // TODO(roasbeef): maybe can use this to extend HORNET with additiona control signals + // for LN nodes? + controlType uint8 + hops uint8 + nonce [8]byte // either interpreted as EXP or nonce, little-endian? idk +} + +// DataPacket... +type DataPacket struct { + Chdr CommonHeader + Ahdr AnonymousHeader // TODO(roasbeef): MAC in ahdr includes the chdr? + Onion [FSLength * NumMaxHops]byte // TODO(roasbeef): or, is it NumMaxHops - 1? +} + +// SessionSetupPacket... +type SessionSetupPacket struct { + Chdr CommonHeader + Shdr SphinxHeader + Sp SphinxPayload + FsPayload [FSLength * NumMaxHops]byte // ? r*c + // TODO(roabeef): hmm does this implcitly mean messages are a max of 48 bytes? +} + +// will add other LN specific control packets below, I guess