@@ -3,6 +3,7 @@ package main
33import (
44 "bytes"
55 "encoding/hex"
6+ "encoding/json"
67 "fmt"
78 "io/ioutil"
89 "log"
@@ -14,6 +15,68 @@ import (
1415 sphinx "github.com/lightningnetwork/lightning-onion"
1516)
1617
18+ type OnionHopSpec struct {
19+ Realm int `json:"realm"`
20+ PublicKey string `json:"pubkey"`
21+ Payload string `json:"payload"`
22+ }
23+
24+ type OnionSpec struct {
25+ SessionKey string `json:"session_key,omitempty"`
26+ Hops []OnionHopSpec `json:"hops"`
27+ }
28+
29+ func parseOnionSpec (spec OnionSpec ) (* sphinx.PaymentPath , * btcec.PrivateKey , error ) {
30+ var path sphinx.PaymentPath
31+ var binSessionKey []byte
32+ var err error
33+
34+ if spec .SessionKey != "" {
35+ binSessionKey , err = hex .DecodeString (spec .SessionKey )
36+ if err != nil {
37+ log .Fatalf ("Unable to decode the sessionKey %v: %v\n " , spec .SessionKey , err )
38+ }
39+
40+ if len (binSessionKey ) != 32 {
41+ log .Fatalf ("Session key must be a 32 byte hex string: %v\n " , spec .SessionKey )
42+ }
43+ } else {
44+ binSessionKey = bytes .Repeat ([]byte {'A' }, 32 )
45+ }
46+
47+ sessionKey , _ := btcec .PrivKeyFromBytes (btcec .S256 (), binSessionKey )
48+
49+ for i , hop := range spec .Hops {
50+ binKey , err := hex .DecodeString (hop .PublicKey )
51+ if err != nil || len (binKey ) != 33 {
52+ log .Fatalf ("%s is not a valid hex pubkey %s" , hop .PublicKey , err )
53+ }
54+
55+ pubkey , err := btcec .ParsePubKey (binKey , btcec .S256 ())
56+ if err != nil {
57+ log .Fatalf ("%s is not a valid hex pubkey %s" , hop .PublicKey , err )
58+ }
59+
60+ path [i ].NodePub = * pubkey
61+
62+ payload , err := hex .DecodeString (hop .Payload )
63+ if err != nil {
64+ log .Fatalf ("%s is not a valid hex payload %s" ,
65+ hop .Payload , err )
66+ }
67+
68+ hopPayload , err := sphinx .NewHopPayload (nil , payload )
69+ if err != nil {
70+ log .Fatalf ("unable to make payload: %v" , err )
71+ }
72+
73+ path [i ].HopPayload = hopPayload
74+
75+ fmt .Fprintf (os .Stderr , "Node %d pubkey %x\n " , i , pubkey .SerializeCompressed ())
76+ }
77+ return & path , sessionKey , nil
78+ }
79+
1780// main implements a simple command line utility that can be used in order to
1881// either generate a fresh mix-header or decode and fully process an existing
1982// one given a private key.
@@ -22,44 +85,33 @@ func main() {
2285
2386 assocData := bytes .Repeat ([]byte {'B' }, 32 )
2487
25- if len (args ) == 1 {
26- fmt .Printf ("Usage: %s (generate|decode) <private-keys>\n " , args [0 ])
88+ if len (args ) < 3 {
89+ fmt .Printf ("Usage: %s (generate|decode) <input-file>\n " , args [0 ])
90+ return
2791 } else if args [1 ] == "generate" {
28- var path sphinx.PaymentPath
29- for i , hexKey := range args [2 :] {
30- binKey , err := hex .DecodeString (hexKey )
31- if err != nil || len (binKey ) != 33 {
32- log .Fatalf ("%s is not a valid hex pubkey %s" , hexKey , err )
33- }
34-
35- pubkey , err := btcec .ParsePubKey (binKey , btcec .S256 ())
36- if err != nil {
37- panic (err )
38- }
39-
40- path [i ] = sphinx.OnionHop {
41- NodePub : * pubkey ,
42- HopData : sphinx.HopData {
43- Realm : [1 ]byte {0x00 },
44- ForwardAmount : uint64 (i ),
45- OutgoingCltv : uint32 (i ),
46- },
47- }
48- copy (path [i ].HopData .NextAddress [:], bytes .Repeat ([]byte {byte (i )}, 8 ))
49-
50- fmt .Fprintf (os .Stderr , "Node %d pubkey %x\n " , i , pubkey .SerializeCompressed ())
51- }
52-
53- sessionKey , _ := btcec .PrivKeyFromBytes (btcec .S256 (), bytes .Repeat ([]byte {'A' }, 32 ))
54-
55- msg , err := sphinx .NewOnionPacket (& path , sessionKey , assocData )
92+ var spec OnionSpec
93+
94+ jsonSpec , err := ioutil .ReadFile (args [2 ])
95+ if err != nil {
96+ log .Fatalf ("Unable to read JSON onion spec from file %v: %v" , args [2 ], err )
97+ }
98+
99+ if err := json .Unmarshal (jsonSpec , & spec ); err != nil {
100+ log .Fatalf ("Unable to parse JSON onion spec: %v" , err )
101+ }
102+
103+ path , sessionKey , err := parseOnionSpec (spec )
104+ if err != nil {
105+ log .Fatalf ("could not parse onion spec: %v" , err )
106+ }
107+
108+ msg , err := sphinx .NewOnionPacket (path , sessionKey , assocData )
56109 if err != nil {
57110 log .Fatalf ("Error creating message: %v" , err )
58111 }
59112
60113 w := bytes .NewBuffer ([]byte {})
61114 err = msg .Encode (w )
62-
63115 if err != nil {
64116 log .Fatalf ("Error serializing message: %v" , err )
65117 }
@@ -78,8 +130,11 @@ func main() {
78130 }
79131
80132 privkey , _ := btcec .PrivKeyFromBytes (btcec .S256 (), binKey )
81- s := sphinx .NewRouter (privkey , & chaincfg .TestNet3Params ,
82- sphinx .NewMemoryReplayLog ())
133+ replayLog := sphinx .NewMemoryReplayLog ()
134+ s := sphinx .NewRouter (privkey , & chaincfg .TestNet3Params , replayLog )
135+
136+ replayLog .Start ()
137+ defer replayLog .Stop ()
83138
84139 var packet sphinx.OnionPacket
85140 err = packet .Decode (bytes .NewBuffer (binMsg ))
0 commit comments