diff --git a/V2.go b/V2.go index 11dc1f7..c28840e 100644 --- a/V2.go +++ b/V2.go @@ -24,7 +24,6 @@ func CreateAddressV2(userKey, muunKey *HDPublicKey) (MuunAddress, error) { address: address.String(), version: addressV2, derivationPath: userKey.Path, - redeemScript: script, }, nil } diff --git a/V2_test.go b/V2_test.go index acd34fd..8ffdeb0 100644 --- a/V2_test.go +++ b/V2_test.go @@ -1,7 +1,6 @@ package libwallet import ( - "encoding/hex" "reflect" "testing" ) @@ -18,13 +17,10 @@ func Test_CreateAddressV2(t *testing.T) { v2EncodedScript = "5221029fa5af7a34c142c1ce348b360abeb7de01df25b1d50129e58a67a6b846c9303b21025714f6b3670d4a38f5e2d6e8f239c9fc072543ce33dca54fcb4f4886a5cb87a652ae" ) - v2Script := make([]byte, 71) - hex.Decode(v2Script[:], []byte(v2EncodedScript)) - - baseMuunKey, _ := NewHDPublicKeyFromString(encodedMuunKey, basePath) + baseMuunKey, _ := NewHDPublicKeyFromString(encodedMuunKey, basePath, Regtest()) muunKey, _ := baseMuunKey.DeriveTo(addressPath) - baseUserKey, _ := NewHDPrivateKeyFromString(encodedUserKey, basePath) + baseUserKey, _ := NewHDPrivateKeyFromString(encodedUserKey, basePath, Regtest()) userKey, _ := baseUserKey.DeriveTo(addressPath) type args struct { @@ -39,7 +35,7 @@ func Test_CreateAddressV2(t *testing.T) { }{ {name: "gen address", args: args{userKey: userKey.PublicKey(), muunKey: muunKey}, - want: &muunAddress{address: originAddress, derivationPath: addressPath, version: addressV2, redeemScript: v2Script}}, + want: &muunAddress{address: originAddress, derivationPath: addressPath, version: addressV2}}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/V3.go b/V3.go index 5f01805..262e21a 100644 --- a/V3.go +++ b/V3.go @@ -24,7 +24,6 @@ func CreateAddressV3(userKey, muunKey *HDPublicKey) (MuunAddress, error) { address: address.EncodeAddress(), version: addressV3, derivationPath: userKey.Path, - redeemScript: redeemScript, }, nil } @@ -48,7 +47,6 @@ func addUserSignatureInputV3(input Input, index int, tx *wire.MsgTx, privateKey return nil, errors.Errorf("muun signature must be present") } - witnessScript, err := createWitnessScriptV3(privateKey.PublicKey(), muunKey) if err != nil { return nil, err @@ -77,7 +75,7 @@ func signInputV3(input Input, index int, tx *wire.MsgTx, userKey *HDPublicKey, m redeemScript, err := createRedeemScriptV3(userKey, muunKey) if err != nil { - return nil, errors.Wrapf(err, "failed to build reedem script for signing") + return nil, errors.Wrapf(err, "failed to build reedem script for signing") } return signNonNativeSegwitInput(input, index, tx, signingKey, redeemScript, witnessScript) diff --git a/V3_test.go b/V3_test.go index 5faf4a6..b5a5d3a 100644 --- a/V3_test.go +++ b/V3_test.go @@ -1,7 +1,6 @@ package libwallet import ( - "encoding/hex" "reflect" "testing" ) @@ -18,13 +17,10 @@ func Test_CreateAddressV3(t *testing.T) { v3EncodedScript = "0020e1fbfbd395aff8b4087fee3e4488815ef659b559b3cd0d6800b5a591efd99f38" ) - v3Script := make([]byte, 34) - hex.Decode(v3Script[:], []byte(v3EncodedScript)) - - baseMuunKey, _ := NewHDPublicKeyFromString(baseCosigningPK, basePath) + baseMuunKey, _ := NewHDPublicKeyFromString(baseCosigningPK, basePath, Regtest()) muunKey, _ := baseMuunKey.DeriveTo(addressPath) - baseUserKey, _ := NewHDPublicKeyFromString(basePK, basePath) + baseUserKey, _ := NewHDPublicKeyFromString(basePK, basePath, Regtest()) userKey, _ := baseUserKey.DeriveTo(addressPath) type args struct { @@ -39,7 +35,7 @@ func Test_CreateAddressV3(t *testing.T) { }{ {name: "gen address", args: args{userKey: userKey, muunKey: muunKey}, - want: &muunAddress{address: v3Address, derivationPath: addressPath, version: addressV3, redeemScript: v3Script}}, + want: &muunAddress{address: v3Address, derivationPath: addressPath, version: addressV3}}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/V4.go b/V4.go new file mode 100644 index 0000000..3fbf9be --- /dev/null +++ b/V4.go @@ -0,0 +1,71 @@ +package libwallet + +import ( + "crypto/sha256" + + "github.com/btcsuite/btcutil" + + "github.com/pkg/errors" + + "github.com/btcsuite/btcd/wire" +) + +func CreateAddressV4(userKey, muunKey *HDPublicKey) (MuunAddress, error) { + + witnessScript, err := createWitnessScriptV4(userKey, muunKey) + if err != nil { + return nil, errors.Wrapf(err, "failed to generate witness script v4") + } + witnessScript256 := sha256.Sum256(witnessScript) + + address, err := btcutil.NewAddressWitnessScriptHash(witnessScript256[:], userKey.Network.network) + if err != nil { + return nil, err + } + + return &muunAddress{ + address: address.EncodeAddress(), + version: addressV4, + derivationPath: userKey.Path, + }, nil +} + +func createWitnessScriptV4(userKey, muunKey *HDPublicKey) ([]byte, error) { + // createRedeemScriptV2 creates a valid script for V2, V3 and V4 schemes + return createRedeemScriptV2(userKey, muunKey) +} + +func addUserSignatureInputV4(input Input, index int, tx *wire.MsgTx, privateKey *HDPrivateKey, muunKey *HDPublicKey) (*wire.TxIn, error) { + + if len(input.MuunSignature()) == 0 { + return nil, errors.Errorf("muun signature must be present") + } + + witnessScript, err := createWitnessScriptV4(privateKey.PublicKey(), muunKey) + if err != nil { + return nil, err + } + + sig, err := signInputV4(input, index, tx, privateKey.PublicKey(), muunKey, privateKey) + if err != nil { + return nil, err + } + + zeroByteArray := []byte{} + + txInput := tx.TxIn[index] + txInput.Witness = wire.TxWitness{zeroByteArray, sig, input.MuunSignature(), witnessScript} + + return txInput, nil +} + +func signInputV4(input Input, index int, tx *wire.MsgTx, userKey *HDPublicKey, muunKey *HDPublicKey, + signingKey *HDPrivateKey) ([]byte, error) { + + witnessScript, err := createWitnessScriptV4(userKey, muunKey) + if err != nil { + return nil, err + } + + return signNativeSegwitInput(input, index, tx, signingKey, witnessScript) +} diff --git a/V4_test.go b/V4_test.go new file mode 100644 index 0000000..e5e9b85 --- /dev/null +++ b/V4_test.go @@ -0,0 +1,50 @@ +package libwallet + +import ( + "reflect" + "testing" +) + +func TestCreateAddressV4(t *testing.T) { + const ( + addressPath = "m/schema:1'/recovery:1'/external:1/2" + + v4Address = "bcrt1qrs3vk4dzv70syck2qdz3g06tgckq4pftenuk5p77st9glnskpvtqe2tvvk" + basePK = "tpubDBf5wCeqg3KrLJiXaveDzD5JtFJ1ss9NVvFMx4RYS73SjwPEEawcAQ7V1B5DGM4gunWDeYNrnkc49sUaf7mS1wUKiJJQD6WEctExUQoLvrg" + baseCosigningPK = "tpubDB22PFkUaHoB7sgxh7exCivV5rAevVSzbB8WkFCCdbHq39r8xnYexiot4NGbi8PM6E1ySVeaHsoDeMYb6EMndpFrzVmuX8iQNExzwNpU61B" + basePath = "m/schema:1'/recovery:1'" + ) + + baseMuunKey, _ := NewHDPublicKeyFromString(baseCosigningPK, basePath, Regtest()) + muunKey, _ := baseMuunKey.DeriveTo(addressPath) + + baseUserKey, _ := NewHDPublicKeyFromString(basePK, basePath, Regtest()) + userKey, _ := baseUserKey.DeriveTo(addressPath) + + type args struct { + userKey *HDPublicKey + muunKey *HDPublicKey + } + tests := []struct { + name string + args args + want MuunAddress + wantErr bool + }{ + {name: "gen bech32 address", + args: args{userKey: userKey, muunKey: muunKey}, + want: &muunAddress{address: v4Address, derivationPath: addressPath, version: addressV4}}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := CreateAddressV4(tt.args.userKey, tt.args.muunKey) + if (err != nil) != tt.wantErr { + t.Errorf("CreateAddressV4() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("CreateAddressV4() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/address.go b/address.go index 8201bb0..b047a87 100644 --- a/address.go +++ b/address.go @@ -13,20 +13,27 @@ import ( "github.com/pkg/errors" ) +// These constants are here for clients usage. +const ( + AddressVersionSwapsV1 = 101 + AddressVersionSwapsV2 = 102 +) + type AddressVersion int const ( - addressV1 AddressVersion = 1 - addressV2 AddressVersion = 2 - addressV3 AddressVersion = 3 - addressSubmarineSwap AddressVersion = 101 + addressV1 AddressVersion = 1 + addressV2 AddressVersion = 2 + addressV3 AddressVersion = 3 + addressV4 AddressVersion = 4 + addressSubmarineSwapV1 AddressVersion = AddressVersionSwapsV1 + addressSubmarineSwapV2 AddressVersion = AddressVersionSwapsV2 ) type muunAddress struct { version AddressVersion derivationPath string address string - redeemScript []byte } func newMuunAddress(version AddressVersion, userPublicKey, muunPublicKey *HDPublicKey) (MuunAddress, error) { @@ -41,8 +48,12 @@ func newMuunAddress(version AddressVersion, userPublicKey, muunPublicKey *HDPubl return CreateAddressV2(userPublicKey, muunPublicKey) case addressV3: return CreateAddressV3(userPublicKey, muunPublicKey) - case addressSubmarineSwap: - return CreateAddressSubmarineSwap(userPublicKey) + case addressV4: + return CreateAddressV4(userPublicKey, muunPublicKey) + case addressSubmarineSwapV1: + return nil, errors.Errorf("can't manually create a submarine swap v1 address") + case addressSubmarineSwapV2: + return nil, errors.Errorf("can't manually create a submarine swap v2 address") } return nil, errors.Errorf("unknown version %v", version) @@ -60,10 +71,6 @@ func (a *muunAddress) Address() string { return a.address } -func (a *muunAddress) RedeemScript() []byte { - return a.redeemScript -} - // MuunPaymentURI is muun's uri struct type MuunPaymentURI struct { Address string @@ -127,7 +134,7 @@ func GetPaymentURI(address string, network *Network) (*MuunPaymentURI, error) { invoice, err := ParseInvoice(queryValues["lightning"][0], network) if err == nil { - return &MuunPaymentURI{Invoice:invoice}, nil + return &MuunPaymentURI{Invoice: invoice}, nil } } @@ -240,9 +247,7 @@ func getAddressFromScript(script []byte, network *Network) (string, error) { func normalizeAddress(rawAddress string) string { newAddress := rawAddress - if strings.Contains(newAddress, muunScheme) { - newAddress = strings.Replace(newAddress, muunScheme, bitcoinScheme, 1) - } + newAddress = strings.Replace(newAddress, muunScheme, bitcoinScheme, 1) if !strings.Contains(newAddress, bitcoinScheme) { newAddress = bitcoinScheme + rawAddress diff --git a/bip70.pb.go b/bip70.pb.go index ce53759..c216384 100644 --- a/bip70.pb.go +++ b/bip70.pb.go @@ -55,22 +55,6 @@ func (m *Output) XXX_DiscardUnknown() { var xxx_messageInfo_Output proto.InternalMessageInfo -const Default_Output_Amount uint64 = 0 - -func (m *Output) GetAmount() uint64 { - if m != nil && m.Amount != nil { - return *m.Amount - } - return Default_Output_Amount -} - -func (m *Output) GetScript() []byte { - if m != nil { - return m.Script - } - return nil -} - type PaymentDetails struct { Network *string `protobuf:"bytes,1,opt,name=network,def=main" json:"network,omitempty"` Outputs []*Output `protobuf:"bytes,2,rep,name=outputs" json:"outputs,omitempty"` @@ -153,13 +137,6 @@ func (m *PaymentDetails) GetPaymentUrl() string { return "" } -func (m *PaymentDetails) GetMerchantData() []byte { - if m != nil { - return m.MerchantData - } - return nil -} - type PaymentRequest struct { PaymentDetailsVersion *uint32 `protobuf:"varint,1,opt,name=payment_details_version,json=paymentDetailsVersion,def=1" json:"payment_details_version,omitempty"` PkiType *string `protobuf:"bytes,2,opt,name=pki_type,json=pkiType,def=none" json:"pki_type,omitempty"` @@ -213,26 +190,6 @@ func (m *PaymentRequest) GetPkiType() string { return Default_PaymentRequest_PkiType } -func (m *PaymentRequest) GetPkiData() []byte { - if m != nil { - return m.PkiData - } - return nil -} - -func (m *PaymentRequest) GetSerializedPaymentDetails() []byte { - if m != nil { - return m.SerializedPaymentDetails - } - return nil -} - -func (m *PaymentRequest) GetSignature() []byte { - if m != nil { - return m.Signature - } - return nil -} type X509Certificates struct { Certificate [][]byte `protobuf:"bytes,1,rep,name=certificate" json:"certificate,omitempty"` @@ -308,12 +265,6 @@ func (m *Payment) XXX_DiscardUnknown() { var xxx_messageInfo_Payment proto.InternalMessageInfo -func (m *Payment) GetMerchantData() []byte { - if m != nil { - return m.MerchantData - } - return nil -} func (m *Payment) GetTransactions() [][]byte { if m != nil { @@ -369,13 +320,6 @@ func (m *PaymentACK) XXX_DiscardUnknown() { var xxx_messageInfo_PaymentACK proto.InternalMessageInfo -func (m *PaymentACK) GetPayment() *Payment { - if m != nil { - return m.Payment - } - return nil -} - func (m *PaymentACK) GetMemo() string { if m != nil && m.Memo != nil { return *m.Memo diff --git a/go.mod b/go.mod index 27e0c06..d1c7bc5 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,13 @@ -module github.com/muun/libwallet +module libwallet go 1.12 require ( - github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3 + github.com/btcsuite/btcd v0.20.1-beta github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d + github.com/go-errors/errors v1.0.1 github.com/golang/protobuf v1.3.2 - github.com/lightningnetwork/lnd v0.7.1-beta-rc2 + github.com/lightningnetwork/lnd v0.8.0-beta github.com/pkg/errors v0.8.1 golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7 ) diff --git a/go.sum b/go.sum index b2ef8e0..4a788bd 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= git.schwanenlied.me/yawning/bsaes.git v0.0.0-20180720073208-c0276d75487e/go.mod h1:BWqTsj8PgcPriQJGl7el20J/7TuT1d/hSyFDXMEpoEo= -github.com/NebulousLabs/fastrand v0.0.0-20180208210444-3cf7173006a0/go.mod h1:Bdzq+51GR4/0DIhaICZEOm+OHvXGwwB2trKZ8B4Y6eQ= +github.com/NebulousLabs/fastrand v0.0.0-20181203155948-6fb6489aac4e/go.mod h1:Bdzq+51GR4/0DIhaICZEOm+OHvXGwwB2trKZ8B4Y6eQ= github.com/NebulousLabs/go-upnp v0.0.0-20180202185039-29b680b06c82/go.mod h1:GbuBk21JqF+driLX3XtJYNZjGa45YDoa9IqCTzNSfEc= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Yawning/aez v0.0.0-20180114000226-4dad034d9db2/go.mod h1:9pIqrY6SXNL8vjRQE5Hd/OL5GyK/9MrGUWs87z/eFfk= @@ -10,25 +10,22 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= -github.com/btcsuite/btcd v0.0.0-20180823030728-d81d8877b8f3/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= -github.com/btcsuite/btcd v0.0.0-20181130015935-7d2daa5bfef2/go.mod h1:Jr9bmNVGZ7TH2Ux1QuP0ec+yGgh0gE9FIlkzQiI5bR0= -github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= -github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= -github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= github.com/btcsuite/btcd v0.0.0-20190629003639-c26ffa870fd8/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= -github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3 h1:A/EVblehb75cUgXA5njHPn0kLAsykn6mJGz7rnmW5W0= github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.20.0-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= -github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= -github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d h1:yJzD/yFppdVCf6ApMkVy8cUxV0XrxdP9rVf6D87/Mng= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= -github.com/btcsuite/btcwallet v0.0.0-20180904010540-284e2e0e696e33d5be388f7f3d9a26db703e0c06/go.mod h1:/d7QHZsfUAruXuBhyPITqoYOmJ+nq35qPsJjz/aSpCg= -github.com/btcsuite/btcwallet v0.0.0-20190313032608-acf3b04b0273/go.mod h1:mkOYY8/psBiL5E+Wb0V7M0o+N7NXi2SZJz6+RKkncIc= -github.com/btcsuite/btcwallet v0.0.0-20190319010515-89ab2044f962/go.mod h1:qMi4jGpAO6YRsd81RYDG7o5pBIGqN9faCioJdagLu64= -github.com/btcsuite/btcwallet v0.0.0-20190712034938-7a3a3e82cbb6/go.mod h1:sXVxjjP5YeWqWsiQbQDXvAw6J6Qvr8swu7MONoNaF9k= +github.com/btcsuite/btcwallet v0.10.0/go.mod h1:4TqBEuceheGNdeLNrelliLHJzmXauMM2vtWfuy1pFiM= +github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0/go.mod h1:VufDts7bd/zs3GV13f/lXc/0lXrPnvxD/NvmpG/FEKU= +github.com/btcsuite/btcwallet/wallet/txrules v1.0.0/go.mod h1:UwQE78yCerZ313EXZwEiu3jNAtfXj2n2+c8RWiE/WNA= +github.com/btcsuite/btcwallet/wallet/txsizes v1.0.0/go.mod h1:pauEU8UuMFiThe5PB3EO+gO5kx87Me5NvdQDsTuq6cs= +github.com/btcsuite/btcwallet/walletdb v1.0.0/go.mod h1:bZTy9RyYZh9fLnSua+/CD48TJtYJSHjjYcSaszuxCCk= +github.com/btcsuite/btcwallet/walletdb v1.1.0/go.mod h1:bZTy9RyYZh9fLnSua+/CD48TJtYJSHjjYcSaszuxCCk= +github.com/btcsuite/btcwallet/wtxmgr v1.0.0/go.mod h1:vc4gBprll6BP0UJ+AIGDaySoc7MdAmZf8kelfNb8CFY= github.com/btcsuite/fastsha256 v0.0.0-20160815193821-637e65642941/go.mod h1:QcFA8DZHtuIAdYKCq/BzELOaznRsCvwf4zTPmaYwaig= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/golangcrypto v0.0.0-20150304025918-53f62d9b43e8/go.mod h1:tYvUd8KLhm/oXvUeSEs2VlLghFjQt9+ZaF9ghH0JNjc= @@ -40,12 +37,12 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/coreos/bbolt v0.0.0-20180223184059-7ee3ded59d4835e10f3e7d0f7603c42aa5e83820/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= @@ -57,11 +54,11 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v0.0.0-20180821051752-b27b920f9e71/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/go-cmp v0.2.1-0.20190312032427-6f77996f0c42/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v0.0.0-20170724004829-f2862b476edc/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= @@ -71,11 +68,11 @@ github.com/jackpal/go-nat-pmp v0.0.0-20170405195558-28a68d0c24ad/go.mod h1:QPH04 github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= -github.com/juju/clock v0.0.0-20180808021310-bab88fc67299/go.mod h1:nD0vlnrUjcjJhqN5WuCWZyzfd5AHZAC9/ajvbSx69xA= -github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= -github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= +github.com/juju/clock v0.0.0-20190205081909-9c5c9712527c/go.mod h1:nD0vlnrUjcjJhqN5WuCWZyzfd5AHZAC9/ajvbSx69xA= +github.com/juju/errors v0.0.0-20190806202954-0232dcc7464d/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= +github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= github.com/juju/retry v0.0.0-20180821225755-9058e192b216/go.mod h1:OohPQGsr4pnxwD5YljhQ+TZnuVRYpa5irjugL1Yuif4= -github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= +github.com/juju/testing v0.0.0-20190723135506-ce30eb24acd2/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= github.com/juju/utils v0.0.0-20180820210520-bf9cc5bdd62d/go.mod h1:6/KLg8Wz/y2KVGWEpkK9vMNGkOnu4k/cqs8Z1fKjTOk= github.com/juju/version v0.0.0-20180108022336-b64dbd566305/go.mod h1:kE8gK5X0CImdr7qpSKl3xB2PmpySSmfj7zVbkZFs81U= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= @@ -87,18 +84,13 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lightninglabs/gozmq v0.0.0-20180324010646-462a8a753885/go.mod h1:KUh15naRlx/TmUMFS/p4JJrCrE6F7RGF7rsnvuu45E4= github.com/lightninglabs/gozmq v0.0.0-20190710231225-cea2a031735d/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk= -github.com/lightninglabs/neutrino v0.0.0-20181017011010-4d6069299130/go.mod h1:KJq43Fu9ceitbJsSXMILcT4mGDNI/crKmPIkDOZXFyM= -github.com/lightninglabs/neutrino v0.0.0-20190213031021-ae4583a89cfb/go.mod h1:g6cMQd+hfAU8pQTJAdjm6/EQREhupyd22f+CL0qYFOE= -github.com/lightninglabs/neutrino v0.0.0-20190313035638-e1ad4c33fb18/go.mod h1:v6tz6jbuAubTrRpX8ke2KH9sJxml8KlPQTKgo9mAp1Q= -github.com/lightninglabs/neutrino v0.0.0-20190725230401-ddf667a8b5c4/go.mod h1:vzLU75ll8qbRJIzW5dvK/UXtR9c2FecJ6VNOM8chyVM= -github.com/lightningnetwork/lightning-onion v0.0.0-20190703000913-ecc936dc56c9/go.mod h1:Sooe/CoCqa85JxqHV+IBR2HW+6t2Cv+36awSmoccswM= -github.com/lightningnetwork/lnd v0.7.1-beta-rc2 h1:N0AuHo4wI6TogabvOfpwg1LkR3RxGCvqYq0Wb7GL+ck= -github.com/lightningnetwork/lnd v0.7.1-beta-rc2/go.mod h1:ODASBFcJwVlb4aqO3m090whpP2kfA9zEvmG/pj+fOfg= +github.com/lightninglabs/neutrino v0.10.0/go.mod h1:C3KhCMk1Mcx3j8v0qRVWM1Ow6rIJSvSPnUAq00ZNAfk= +github.com/lightningnetwork/lightning-onion v0.0.0-20190909101754-850081b08b6a/go.mod h1:rigfi6Af/KqsF7Za0hOgcyq2PNH4AN70AaMRxcJkff4= +github.com/lightningnetwork/lnd v0.8.0-beta h1:HmmhSRTq48qobqQF8YLqNa8eKU8dDBNbWWpr2VzycJM= +github.com/lightningnetwork/lnd v0.8.0-beta/go.mod h1:nq06y2BDv7vwWeMmwgB7P3pT7/Uj7sGf5FzHISVD6t4= github.com/lightningnetwork/lnd/queue v1.0.1/go.mod h1:vaQwexir73flPW43Mrm7JOgJHmcEFBWWSl9HlyASoms= github.com/lightningnetwork/lnd/ticker v1.0.0/go.mod h1:iaLXJiVgI1sPANIF2qYYUJXjoksPNvGNYowB8aRbpX0= -github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 h1:sjOGyegMIhvgfq5oaue6Td+hxZuf3tDC8lAPrFldqFw= github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796/go.mod h1:3p7ZTf9V1sNPI5H8P3NkTFF4LuwMdPl2DodF60qAKqY= github.com/ltcsuite/ltcutil v0.0.0-20181217130922-17f3b04680b6/go.mod h1:8Vg/LTOO0KYa/vlHWJ6XZAevPQThGH5sufO0Hrou/lA= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -123,19 +115,16 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/tv42/zbase32 v0.0.0-20160707012821-501572607d02/go.mod h1:tHlrkM198S068ZqfrO6S8HsoJq2bF3ETfTL+kt4tInY= github.com/urfave/cli v1.18.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -go.etcd.io/bbolt v1.3.0/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7 h1:0hQKqeLdqlt5iIwVOBErRisrHJAN57yOiPRQItI20fU= @@ -144,7 +133,6 @@ golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180821023952-922f4815f713/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -156,16 +144,15 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180821140842-3b58ed4ad339/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -173,18 +160,16 @@ golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGm google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4= -google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= -google.golang.org/grpc v1.18.0 h1:IZl7mfBGfbhYx2p2rKRtYgDFw6SBz+kclmxYrCksPPA= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v1 v1.0.0/go.mod h1:CxwszS/Xz1C49Ucd2i6Zil5UToP1EmyrFhKaMVbg1mk= +gopkg.in/errgo.v1 v1.0.1/go.mod h1:3NjfXwocQRYAPTq4/fzX+CwUhPRcR/azYRhj8G+LqMo= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/macaroon-bakery.v2 v2.0.1/go.mod h1:B4/T17l+ZWGwxFSZQmlBwp25x+og7OkhETfr3S9MbIA= gopkg.in/macaroon.v2 v2.0.0/go.mod h1:+I6LnTMkm/uV5ew/0nsulNjL16SK4+C8yDmRUzHR17I= -gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= +gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/hdprivatekey.go b/hdprivatekey.go index 1ce2ade..bfe8292 100644 --- a/hdprivatekey.go +++ b/hdprivatekey.go @@ -39,9 +39,9 @@ func NewHDPrivateKeyFromBytes(rawKey, chainCode []byte, network *Network) (*HDPr // NewHDPrivateKeyFromString creates an HD priv key from a base58-encoded string // If the parsed key is public, it returns an error -func NewHDPrivateKeyFromString(str, path string) (*HDPrivateKey, error) { +func NewHDPrivateKeyFromString(str, path string, network *Network) (*HDPrivateKey, error) { - key, network, err := keyFromString(str) + key, _, err := keyFromString(str) if err != nil { return nil, err } diff --git a/hdprivatekey_test.go b/hdprivatekey_test.go index b3b69b0..9e89961 100644 --- a/hdprivatekey_test.go +++ b/hdprivatekey_test.go @@ -71,7 +71,7 @@ func TestNewHDPrivateKeySerialization(t *testing.T) { }) t.Run("invalid key deserialization", func(t *testing.T) { - badKey, err := NewHDPrivateKeyFromString("fooo", "m") + badKey, err := NewHDPrivateKeyFromString("fooo", "m", Regtest()) if badKey != nil || err == nil { t.Errorf("bad key should only return error returned %v, %v", badKey, err) } @@ -81,17 +81,17 @@ func TestNewHDPrivateKeySerialization(t *testing.T) { randomKey.key.SetNet(&chaincfg.Params{HDPrivateKeyID: [4]byte{1, 2, 3, 4}}) // Parsing it should fail since we check we know the chain - badKey, err = NewHDPrivateKeyFromString(randomKey.String(), "m") + badKey, err = NewHDPrivateKeyFromString(randomKey.String(), "m", Regtest()) if badKey != nil || err == nil { t.Errorf("expected failure when parsing key with fake chain, got %v, %v", badKey, err) } - badKey, err = NewHDPrivateKeyFromString(vector1FirstPub, "m") + badKey, err = NewHDPrivateKeyFromString(vector1FirstPub, "m", Regtest()) if badKey != nil || err == nil { t.Errorf("expected failure when parsing pub key as priv key, got %v, %v", badKey, err) } - badPubKey, err := NewHDPublicKeyFromString(vector1FirstPriv, "m") + badPubKey, err := NewHDPublicKeyFromString(vector1FirstPriv, "m", Regtest()) if badPubKey != nil || err == nil { t.Errorf("expected failure when parsing priv key as pub key, got %v, %v", badPubKey, err) } @@ -103,7 +103,7 @@ func TestNewHDPrivateKeySerialization(t *testing.T) { randomKey.key.SetNet(&chaincfg.RegressionNetParams) // Parsing it should fail since we check we know the chain - key, err := NewHDPrivateKeyFromString(randomKey.String(), "m") + key, err := NewHDPrivateKeyFromString(randomKey.String(), "m", Regtest()) if key == nil || err != nil { t.Errorf("failed to parse regtest key, got err %v", err) } @@ -117,7 +117,7 @@ func TestNewHDPrivateKeySerialization(t *testing.T) { } serialized := randomKey.String() - deserialized, err := NewHDPrivateKeyFromString(serialized, "m") + deserialized, err := NewHDPrivateKeyFromString(serialized, "m", Regtest()) if err != nil { t.Fatalf("failed to deserialize key") } @@ -129,7 +129,7 @@ func TestNewHDPrivateKeySerialization(t *testing.T) { t.Run("Child key serialization", func(t *testing.T) { root, err := NewHDPrivateKeyFromString( - "tprv8ZgxMBicQKsPdGCzsJ31BsQnFL1TSQ82dfsZYTtsWJ1T8g7xTfnV19gf8nYPqzkzk6yLL9kzDYshmUrYyXt7uXsGbk9eN7juRxg9sjaxSjn", "m") + "tprv8ZgxMBicQKsPdGCzsJ31BsQnFL1TSQ82dfsZYTtsWJ1T8g7xTfnV19gf8nYPqzkzk6yLL9kzDYshmUrYyXt7uXsGbk9eN7juRxg9sjaxSjn", "m", Regtest()) if err != nil { t.Fatalf("failed to parse root key") } @@ -142,7 +142,7 @@ func TestNewHDPrivateKeySerialization(t *testing.T) { t.Fatalf("derived key doesn't match serialized") } - decodedKey, _ := NewHDPrivateKeyFromString(encodedKey, "m") + decodedKey, _ := NewHDPrivateKeyFromString(encodedKey, "m", Regtest()) if decodedKey.String() != encodedKey { t.Fatalf("decoded key doesn't match encoded string") @@ -167,7 +167,7 @@ func TestKeyDerivation(t *testing.T) { } t.Run("vector1", func(t *testing.T) { - privKey, _ := NewHDPrivateKeyFromString(vector1PrivKey, "m") + privKey, _ := NewHDPrivateKeyFromString(vector1PrivKey, "m", Regtest()) if privKey.PublicKey().String() != vector1PubKey { t.Errorf("pub key doesnt match") } @@ -177,7 +177,7 @@ func TestKeyDerivation(t *testing.T) { }) t.Run("vector2", func(t *testing.T) { - privKey, _ := NewHDPrivateKeyFromString(vector2PrivKey, "m") + privKey, _ := NewHDPrivateKeyFromString(vector2PrivKey, "m", Regtest()) if privKey.PublicKey().String() != vector2PubKey { t.Errorf("pub key doesnt match") } @@ -188,7 +188,7 @@ func TestKeyDerivation(t *testing.T) { }) t.Run("vector3", func(t *testing.T) { - privKey, _ := NewHDPrivateKeyFromString(vector3PrivKey, "m") + privKey, _ := NewHDPrivateKeyFromString(vector3PrivKey, "m", Regtest()) if privKey.PublicKey().String() != vector3PubKey { t.Errorf("pub key doesnt match") } @@ -199,7 +199,7 @@ func TestKeyDerivation(t *testing.T) { func TestSymmetricDerivation(t *testing.T) { - privKey, _ := NewHDPrivateKeyFromString(symmetricPrivKey, "m") + privKey, _ := NewHDPrivateKeyFromString(symmetricPrivKey, "m", Regtest()) pubKey := privKey.PublicKey() t.Run("basic check", func(t *testing.T) { @@ -253,7 +253,7 @@ func TestSymmetricDerivation(t *testing.T) { }) testBadDerivation := func(t *testing.T, path string) { - privKey, _ := NewHDPrivateKeyFromString(vector1PrivKey, "m/123") + privKey, _ := NewHDPrivateKeyFromString(vector1PrivKey, "m/123", Regtest()) pubKey := privKey.PublicKey() badKey, err := privKey.DeriveTo(path) diff --git a/hdpublickey.go b/hdpublickey.go index 09703ac..dd18749 100644 --- a/hdpublickey.go +++ b/hdpublickey.go @@ -18,9 +18,9 @@ type HDPublicKey struct { // NewHDPublicKeyFromString creates an HD pub key from a base58-encoded string // If the parsed key is private, it returns an error -func NewHDPublicKeyFromString(str, path string) (*HDPublicKey, error) { +func NewHDPublicKeyFromString(str, path string, network *Network) (*HDPublicKey, error) { - key, network, err := keyFromString(str) + key, _, err := keyFromString(str) if err != nil { return nil, err } diff --git a/invoice.go b/invoice.go index a6ae0dc..73fa989 100644 --- a/invoice.go +++ b/invoice.go @@ -27,7 +27,7 @@ func ParseInvoice(invoice string, network *Network) (*Invoice, error) { if strings.HasPrefix(strings.ToLower(invoice), lightningScheme) { // Remove lightning scheme from rawInvoice - invoice = invoice[len(lightningScheme):len(invoice)] + invoice = invoice[len(lightningScheme):] } parsedInvoice, err := zpay32.Decode(invoice, network.network) diff --git a/keycrypter.go b/keycrypter.go index c20f2f7..ac38abd 100644 --- a/keycrypter.go +++ b/keycrypter.go @@ -64,7 +64,7 @@ func KeyEncrypt(key *HDPrivateKey, passphrase string) (string, error) { } // KeyDecrypt decrypts a key encrypted with KeyEncrypt -func KeyDecrypt(value, passphrase string) (*DecryptedKey, error) { +func KeyDecrypt(value, passphrase string, network *Network) (*DecryptedKey, error) { elements := strings.Split(value, seperator) @@ -126,7 +126,7 @@ func KeyDecrypt(value, passphrase string) (*DecryptedKey, error) { encodedPrivateKey := string(decryptedBytes[:]) path := string(pathBytes[:]) - privateKey, err := NewHDPrivateKeyFromString(encodedPrivateKey, path) + privateKey, err := NewHDPrivateKeyFromString(encodedPrivateKey, path, network) if err != nil { return nil, errors.New("KeyCrypter: failed to decode pk: " + err.Error()) } diff --git a/keycrypter_test.go b/keycrypter_test.go index 05aa4ff..11d6011 100644 --- a/keycrypter_test.go +++ b/keycrypter_test.go @@ -29,7 +29,7 @@ func TestKeyCrypt(t *testing.T) { t.Fatalf("KeyEncrypt() error = %v", err) } - decrypted, err := KeyDecrypt(encrypted, testPassphrase) + decrypted, err := KeyDecrypt(encrypted, testPassphrase, Regtest()) if err != nil { t.Fatalf("KeyEncrypt() error = %v", err) } @@ -50,7 +50,7 @@ func TestKeyCrypt(t *testing.T) { t.Fatalf("KeyEncrypt() error = %v", err) } - _, err = KeyDecrypt(encrypted, testPassphrase+"foo") + _, err = KeyDecrypt(encrypted, testPassphrase+"foo", Regtest()) if err == nil { t.Fatalf("expected decryption error") } diff --git a/partiallysignedtransaction.go b/partiallysignedtransaction.go index dc86e86..160c030 100644 --- a/partiallysignedtransaction.go +++ b/partiallysignedtransaction.go @@ -25,19 +25,29 @@ type Outpoint interface { Amount() int64 } -type InputSubmarineSwap interface { +type InputSubmarineSwapV1 interface { RefundAddress() string PaymentHash256() []byte ServerPublicKey() []byte LockTime() int64 } +type InputSubmarineSwapV2 interface { + PaymentHash256() []byte + UserPublicKey() []byte + MuunPublicKey() []byte + ServerPublicKey() []byte + BlocksForExpiration() int64 + ServerSignature() []byte +} + type Input interface { OutPoint() Outpoint Address() MuunAddress UserSignature() []byte MuunSignature() []byte - SubmarineSwap() InputSubmarineSwap + SubmarineSwapV1() InputSubmarineSwapV1 + SubmarineSwapV2() InputSubmarineSwapV2 } type PartiallySignedTransaction struct { @@ -93,8 +103,12 @@ func (p *PartiallySignedTransaction) Sign(key *HDPrivateKey, muunKey *HDPublicKe txIn, err = addUserSignatureInputV2(input, i, p.tx, derivedKey, derivedMuunKey) case addressV3: txIn, err = addUserSignatureInputV3(input, i, p.tx, derivedKey, derivedMuunKey) - case addressSubmarineSwap: - txIn, err = addUserSignatureInputSubmarineSwap(input, i, p.tx, derivedKey, derivedMuunKey) + case addressV4: + txIn, err = addUserSignatureInputV4(input, i, p.tx, derivedKey, derivedMuunKey) + case addressSubmarineSwapV1: + txIn, err = addUserSignatureInputSubmarineSwapV1(input, i, p.tx, derivedKey, derivedMuunKey) + case addressSubmarineSwapV2: + txIn, err = addUserSignatureInputSubmarineSwapV2(input, i, p.tx, derivedKey, derivedMuunKey) default: return nil, errors.Errorf("cant sign transaction of version %v", input.Address().Version()) } @@ -141,9 +155,13 @@ func (p *PartiallySignedTransaction) MuunSignatureForInput(index int, userKey *H return signInputV2(input, index, p.tx, derivedUserKey, derivedMuunKey.PublicKey(), derivedMuunKey) case addressV3: return signInputV3(input, index, p.tx, derivedUserKey, derivedMuunKey.PublicKey(), derivedMuunKey) - case addressSubmarineSwap: - return nil, errors.New("cant sign arbitrary submarine swap inputs") + case addressV4: + return signInputV4(input, index, p.tx, derivedUserKey, derivedMuunKey.PublicKey(), derivedMuunKey) + case addressSubmarineSwapV1: + return nil, errors.New("cant sign arbitrary submarine swap v1 inputs") + case addressSubmarineSwapV2: + return nil, errors.New("cant sign arbitrary submarine swap v2 inputs") } return nil, errors.New("unknown address scheme") -} \ No newline at end of file +} diff --git a/partiallysignedtransaction_test.go b/partiallysignedtransaction_test.go index f3a394d..98617ff 100644 --- a/partiallysignedtransaction_test.go +++ b/partiallysignedtransaction_test.go @@ -3,6 +3,7 @@ package libwallet import ( "bytes" "encoding/hex" + fmt "fmt" "testing" "github.com/btcsuite/btcd/txscript" @@ -14,11 +15,12 @@ const ( ) type input struct { - outpoint outpoint - address muunAddress - userSignature []byte - muunSignature []byte - submarineSwap inputSubmarineSwap + outpoint outpoint + address muunAddress + userSignature []byte + muunSignature []byte + submarineSwapV1 inputSubmarineSwapV1 + submarineSwapV2 inputSubmarineSwapV2 } func (i *input) OutPoint() Outpoint { @@ -37,8 +39,12 @@ func (i *input) MuunSignature() []byte { return i.muunSignature } -func (i *input) SubmarineSwap() InputSubmarineSwap { - return &i.submarineSwap +func (i *input) SubmarineSwapV1() InputSubmarineSwapV1 { + return &i.submarineSwapV1 +} + +func (i *input) SubmarineSwapV2() InputSubmarineSwapV2 { + return &i.submarineSwapV2 } type outpoint struct { @@ -59,29 +65,62 @@ func (o *outpoint) Amount() int64 { return o.amount } -type inputSubmarineSwap struct { +type inputSubmarineSwapV1 struct { refundAddress string paymentHash256 []byte serverPublicKey []byte lockTime int64 } -func (i *inputSubmarineSwap) RefundAddress() string { +func (i *inputSubmarineSwapV1) RefundAddress() string { return i.refundAddress } -func (i *inputSubmarineSwap) PaymentHash256() []byte { +func (i *inputSubmarineSwapV1) PaymentHash256() []byte { return i.paymentHash256 } -func (i *inputSubmarineSwap) ServerPublicKey() []byte { +func (i *inputSubmarineSwapV1) ServerPublicKey() []byte { return i.serverPublicKey } -func (i *inputSubmarineSwap) LockTime() int64 { +func (i *inputSubmarineSwapV1) LockTime() int64 { return i.lockTime } +type inputSubmarineSwapV2 struct { + paymentHash256 []byte + serverPublicKey []byte + userPublicKey []byte + muunPublicKey []byte + blocksForExpiration int64 + serverSignature []byte +} + +func (i *inputSubmarineSwapV2) PaymentHash256() []byte { + return i.paymentHash256 +} + +func (i *inputSubmarineSwapV2) ServerPublicKey() []byte { + return i.serverPublicKey +} + +func (i *inputSubmarineSwapV2) UserPublicKey() []byte { + return i.userPublicKey +} + +func (i *inputSubmarineSwapV2) MuunPublicKey() []byte { + return i.muunPublicKey +} + +func (i *inputSubmarineSwapV2) BlocksForExpiration() int64 { + return i.blocksForExpiration +} + +func (i *inputSubmarineSwapV2) ServerSignature() []byte { + return i.serverSignature +} + func TestPartillySignedTransaction_SignV1(t *testing.T) { const ( hexTx = "0100000001706bcabdcdcfd519bdb4534f8ace9f8a3cd614e7b00f074cce0a58913eadfffb0100000000ffffffff022cf46905000000001976a914072b22dfb34153d4e084dce8c6655430d37f12d088aca4de8b00000000001976a914fded0987447ef3273cde87bf8b65a11d1fd9caca88ac00000000" @@ -107,7 +146,7 @@ func TestPartillySignedTransaction_SignV1(t *testing.T) { partial, _ := NewPartiallySignedTransaction(hexTx) partial.inputs = inputs - userKey, _ := NewHDPrivateKeyFromString(encodedUserKey, basePath) + userKey, _ := NewHDPrivateKeyFromString(encodedUserKey, basePath, Regtest()) // We dont need to use the muunKey in V1 signedRawTx, err := partial.Sign(userKey, userKey.PublicKey()) @@ -189,8 +228,8 @@ func TestPartiallySignedTransaction_SignV2(t *testing.T) { partial, _ := NewPartiallySignedTransaction(hexTx) partial.inputs = inputs - muunKey, _ := NewHDPublicKeyFromString(encodedMuunKey, basePath) - userKey, _ := NewHDPrivateKeyFromString(encodedUserKey, basePath) + muunKey, _ := NewHDPublicKeyFromString(encodedMuunKey, basePath, Regtest()) + userKey, _ := NewHDPrivateKeyFromString(encodedUserKey, basePath, Regtest()) signedRawTx, err := partial.Sign(userKey, muunKey) if err != nil { @@ -237,8 +276,8 @@ func TestPartiallySignedTransaction_SignV3(t *testing.T) { partial, _ := NewPartiallySignedTransaction(hexTx) partial.inputs = inputs - muunKey, _ := NewHDPublicKeyFromString(encodedMuunKey, basePath) - userKey, _ := NewHDPrivateKeyFromString(encodedUserKey, basePath) + muunKey, _ := NewHDPublicKeyFromString(encodedMuunKey, basePath, Regtest()) + userKey, _ := NewHDPrivateKeyFromString(encodedUserKey, basePath, Regtest()) signedRawTx, err := partial.Sign(userKey, muunKey) if err != nil { @@ -251,7 +290,7 @@ func TestPartiallySignedTransaction_SignV3(t *testing.T) { verifyInput(t, signedTx, hexTx1, txIndex1, 0) } -func TestPartiallySignedTransaction_SignSubmarineSwap(t *testing.T) { +func TestPartiallySignedTransaction_SignSubmarineSwapV1(t *testing.T) { const ( hexTx = "01000000021a608c7d6e40586806c33b3b1036fbd305c37e9d38990d912cc02de7e7cec05e0000000000fffffffff18bce10875329410641316bf7c4d984e00780174b6983080e9225dc26e5bd8c0100000000feffffff01705bc0230000000017a91470fcbc29723c85fdbf9fb5189220f279e9be4508878f030000" @@ -293,8 +332,8 @@ func TestPartiallySignedTransaction_SignSubmarineSwap(t *testing.T) { }, &input{ outpoint: outpoint{index: txIndex2, amount: txAmount2, txId: txOut2}, - address: muunAddress{address: txAddress2, derivationPath: txAddressPath2, version: addressSubmarineSwap}, - submarineSwap: inputSubmarineSwap{ + address: muunAddress{address: txAddress2, derivationPath: txAddressPath2, version: addressSubmarineSwapV1}, + submarineSwapV1: inputSubmarineSwapV1{ refundAddress: txRefundAddress2, paymentHash256: paymentHash2, serverPublicKey: serverPubKey2, @@ -306,8 +345,8 @@ func TestPartiallySignedTransaction_SignSubmarineSwap(t *testing.T) { partial, _ := NewPartiallySignedTransaction(hexTx) partial.inputs = inputs - muunKey, _ := NewHDPublicKeyFromString(encodedMuunKey, basePath) - userKey, _ := NewHDPrivateKeyFromString(encodedUserKey, basePath) + muunKey, _ := NewHDPublicKeyFromString(encodedMuunKey, basePath, Regtest()) + userKey, _ := NewHDPrivateKeyFromString(encodedUserKey, basePath, Regtest()) signedRawTx, err := partial.Sign(userKey, muunKey) if err != nil { @@ -348,3 +387,69 @@ func verifyInput(t *testing.T, signedTx *wire.MsgTx, hexPrevTx string, prevIndex t.Fatalf("failed to verify script: %v", err) } } + +func TestPartiallySignedTransaction_SignSubmarineSwapV2(t *testing.T) { + const ( + hexTx = "010000000001010a1e9552f252c4f94dae951a3a2789263650d69de286ed4813333ac73179b4790000000023220020fc4ea5a79e0de596005a77df25fdc1d76a5bd2ca022b58260830b45dbf48005fffffffff0100000000000000001976a91476e6856729db9c3885fbd72c47bd225990eee4ad88ac03473044022038395a9846c02cc1b87655ea4679f3df127fa5f781c7db3598ee43acc65adab4022051f0f874a8c16544c4ab492b8a091b630703d742599ea17c61b2bfadb747f30e0147304402207bd5a91f032ed3d69a7999d170c696861f36991f6b54e24da4319eaf512ccac402203d3d14c42103261f605b3a870ab10b03ff8b84537575768067e41853d77d2b240187210310df0c435a58758d53821915501301581be8c18b63d5a0dab281aa7f98bcb6e67c210226048275203811ab30a61759f8271280cb754ede8c38b5c51fc662dec441511eac637c76a914f722e6b3c976eba035578a7b268de980682d60b1876375677cac6867029000b275ad76a9141528942b8aef6f523d8050ad6bab416d6199352288ac6800000000" + + txIndex2 = 0 + txAmount2 = 1000 + hexTxOut2 = "79b47931c73a331348ed86e29dd650362689273a1a95ae4df9c452f252951e0a" + hexTx2 = "0100000001b9c3208b3cd1c687d73fec2022ac6ce057c00cf8ae060e5579107a8d99681a7f000000006a473044022042d2e34afb3b66b27641c774b467ce854cfa5d4f9a1eaa462174fa3c688208840220651fdeab3a8134c65431dba040b654d9d21f50343f82bc1870b5280eaff89fc101210209d4e395ce720f13439f4f73b0dac8433f2fa17f094c5fcdaa6965bf96ece088ffffffff02e80300000000000017a914fc7ee7c4ce68ca09559d9e8776f0455039ea18d58718ee052a010000001976a9143447bbd5107cb1572eeb8550f74e5d31a4bf5bd888ac00000000" + txAddressPath2 = "m" + txAddress2 = "2NGGJJARaFRcARRMDeSWQ46LwU46Z9oKNCZ" + txPaymentHashHex2 = "cdb14d5fcf498e8785caff18940bbd713b98b4d425ab0503adb92ab08c5850e3" + txServerPubKeyHex2 = "0226048275203811ab30a61759f8271280cb754ede8c38b5c51fc662dec441511e" + txBlockForExpiration2 = 144 + txServerSignatureHex2 = "304402207bd5a91f032ed3d69a7999d170c696861f36991f6b54e24da4319eaf512ccac402203d3d14c42103261f605b3a870ab10b03ff8b84537575768067e41853d77d2b2401" + + encodedMuunKey = "tpubD6NzVbkrYhZ4Yg872usw1wxNYrpCsUmiG4faYMaogSFwJFX9sz8MrR6GNKg4qUDjb3KUYcC9nrUL7tQYfK441qkFP9pwsw6fb8gTW7vJjXq" + encodedUserKey = "tprv8ZgxMBicQKsPdu1SiZiQbV4K2af648S6jf8Axu7RkgQborzWpQVRzrSvyoYWb5Rmy8VVyFBDjZobn7ZaK3Ax2hLvF9NxJ6gUWNLwgLxRav7" + ) + + txOut2, _ := hex.DecodeString(hexTxOut2) + + paymentHash2, _ := hex.DecodeString(txPaymentHashHex2) + serverPubKey2, _ := hex.DecodeString(txServerPubKeyHex2) + serverSignature2, _ := hex.DecodeString(txServerSignatureHex2) + + muunKey, _ := NewHDPublicKeyFromString(encodedMuunKey, "m", Regtest()) + userKey, _ := NewHDPrivateKeyFromString(encodedUserKey, "m", Regtest()) + + inputs := []Input{ + &input{ + outpoint: outpoint{index: txIndex2, amount: txAmount2, txId: txOut2}, + address: muunAddress{address: txAddress2, derivationPath: txAddressPath2, version: addressSubmarineSwapV2}, + submarineSwapV2: inputSubmarineSwapV2{ + paymentHash256: paymentHash2, + serverPublicKey: serverPubKey2, + userPublicKey: userKey.PublicKey().Raw(), + muunPublicKey: muunKey.Raw(), + blocksForExpiration: txBlockForExpiration2, + serverSignature: serverSignature2, + }, + }, + } + + partial, _ := NewPartiallySignedTransaction(hexTx) + partial.inputs = inputs + + signedRawTx, err := partial.Sign(userKey, muunKey) + + if err != nil { + t.Fatalf("failed to sign tx due to %v", err) + } + + signedTx := wire.NewMsgTx(0) + signedTx.BtcDecode(bytes.NewBuffer(signedRawTx.Bytes), 0, wire.WitnessEncoding) + + verifyInput(t, signedTx, hexTx2, txIndex2, 0) +} + +func TestBlo(t *testing.T) { + hexBlob := "2103285ec73aa7b8e86a37a2919c3cba5da7862d64523c16c1868fbbdde0e5c7b5e57c21028b7c740b590012eaffef072675baaa95aee39508fd049ed1cd698ee26ce33f02ac637c76a914477f2112346a2b3a5969001d322f13e1a96da7bb876375677cac6867029000b275ad76a914a5d78a66701ac212735adeb31112c948b7b9ed7e88ac68" + data, _ := hex.DecodeString(hexBlob) + + str, _ := txscript.DisasmString(data) + fmt.Println(str) +} diff --git a/ripemd160.go b/ripemd160.go index fbd6af4..5abe7e8 100644 --- a/ripemd160.go +++ b/ripemd160.go @@ -1,7 +1,7 @@ package libwallet import ( - hash "golang.org/x/crypto/ripemd160" + hash "golang.org/x/crypto/ripemd160" //lint:ignore SA1019 using deprecated hash function for compatibility ) func ripemd160(data []byte) []byte { diff --git a/segwit.go b/segwit.go index 7dd3f57..5355dd0 100644 --- a/segwit.go +++ b/segwit.go @@ -8,6 +8,22 @@ import ( "github.com/pkg/errors" ) +func signNativeSegwitInput(input Input, index int, tx *wire.MsgTx, privateKey *HDPrivateKey, witnessScript []byte) ([]byte, error) { + + privKey, err := privateKey.key.ECPrivKey() + if err != nil { + return nil, errors.Wrapf(err, "failed to produce EC priv key for signing") + } + + sigHashes := txscript.NewTxSigHashes(tx) + sig, err := txscript.RawTxInWitnessSignature(tx, sigHashes, index, input.OutPoint().Amount(), witnessScript, txscript.SigHashAll, privKey) + if err != nil { + return nil, errors.Wrapf(err, "failed to sign V4 input") + } + + return sig, nil +} + func createNonNativeSegwitRedeemScript(witnessScript []byte) ([]byte, error) { witnessScriptHash := sha256.Sum256(witnessScript) diff --git a/submarineSwap.go b/submarineSwap.go index e60089a..458c311 100644 --- a/submarineSwap.go +++ b/submarineSwap.go @@ -1,14 +1,7 @@ package libwallet import ( - "bytes" - "crypto/sha256" - "encoding/hex" - - "github.com/btcsuite/btcd/txscript" - "github.com/btcsuite/btcd/wire" - "github.com/btcsuite/btcutil" - "github.com/pkg/errors" + "github.com/go-errors/errors" ) type SubmarineSwap interface { @@ -26,190 +19,33 @@ type SubmarineSwapReceiver interface { } type SubmarineSwapFundingOutput interface { + ScriptVersion() int64 + OutputAddress() string OutputAmount() int64 ConfirmationsNeeded() int - UserLockTime() int64 - UserRefundAddress() MuunAddress ServerPaymentHashInHex() string ServerPublicKeyInHex() string -} - -func CreateAddressSubmarineSwap(publicKey *HDPublicKey) (MuunAddress, error) { - pubkey, err := btcutil.NewAddressPubKey(publicKey.Raw(), publicKey.Network.network) - if err != nil { - return nil, err - } - - pubkeyHash := pubkey.AddressPubKeyHash() - address := pubkeyHash.String() - - return &muunAddress{address: address, version: addressSubmarineSwap, derivationPath: publicKey.Path}, nil -} - -func addUserSignatureInputSubmarineSwap(input Input, index int, tx *wire.MsgTx, privateKey *HDPrivateKey, - muunKey *HDPublicKey) (*wire.TxIn, error) { - - submarineSwap := input.SubmarineSwap() - if submarineSwap == nil { - return nil, errors.Errorf("submarine swap data is nil for ss input") - } - - witnessScript, err := createWitnessScriptSubmarineSwap(submarineSwap.RefundAddress(), - submarineSwap.PaymentHash256(), - submarineSwap.ServerPublicKey(), - submarineSwap.LockTime(), - privateKey.Network) - if err != nil { - return nil, err - } - - redeemScript, err := createNonNativeSegwitRedeemScript(witnessScript) - if err != nil { - return nil, errors.Wrapf(err, "failed to build reedem script for signing") - } - - sig, err := signNonNativeSegwitInput(input, index, tx, privateKey, redeemScript, witnessScript) - if err != nil { - return nil, err - } - - txInput := tx.TxIn[index] - txInput.Witness = wire.TxWitness{sig, privateKey.PublicKey().Raw(), witnessScript} - - return txInput, nil -} - -func createRedeemScriptSubmarineSwapForUser(publicKey *HDPublicKey) { - -} - -func createWitnessScriptSubmarineSwap(refundAddress string, paymentHash []byte, swapServerPubKey []byte, lockTime int64, network *Network) ([]byte, error) { - - // It turns out that the payment hash present in an invoice is just the SHA256 of the - // payment preimage, so we still have to do a pass of RIPEMD160 before pushing it to the - // script - paymentHash160 := ripemd160(paymentHash) - decodedRefundAddress, err := btcutil.DecodeAddress(refundAddress, network.network) - if err != nil { - return nil, errors.Wrapf(err, "refund address is invalid") - } - - refundAddressHash := decodedRefundAddress.ScriptAddress() - - builder := txscript.NewScriptBuilder() - builder.AddOp(txscript.OP_DUP) - - // Condition to decide which branch to follow: - builder.AddOp(txscript.OP_HASH160). - AddData(paymentHash160). - AddOp(txscript.OP_EQUAL) - // SubmarineSwap service spending script, for successful LN payments: - builder.AddOp(txscript.OP_IF). - AddOp(txscript.OP_DROP). - AddData(swapServerPubKey) - - // User spending script, for failed LN payments: - builder.AddOp(txscript.OP_ELSE). - AddInt64(lockTime). - AddOp(txscript.OP_CHECKLOCKTIMEVERIFY). - AddOp(txscript.OP_DROP). - AddOp(txscript.OP_DUP). - AddOp(txscript.OP_HASH160). - AddData(refundAddressHash). - AddOp(txscript.OP_EQUALVERIFY) + UserLockTime() int64 - // Final verification for both branches: - builder.AddOp(txscript.OP_ENDIF). - AddOp(txscript.OP_CHECKSIG) + // v1 only + UserRefundAddress() MuunAddress - return builder.Script() + // v2 only + ExpirationInBlocks() int64 + UserPublicKey() *HDPublicKey + MuunPublicKey() *HDPublicKey } -func ValidateSubmarineSwap(rawInvoice string, userPublicKey *HDPublicKey, muunPublicKey *HDPublicKey, swap SubmarineSwap, network *Network) error { - - invoice, err := ParseInvoice(rawInvoice, network) - if err != nil { - return errors.Wrapf(err, "failed to decode invoice") - } - - // Check the payment hash matches - - serverPaymentHash, err := hex.DecodeString(swap.FundingOutput().ServerPaymentHashInHex()) - if err != nil { - return errors.Wrapf(err, "server payment hash is not valid hex") - } - - if !bytes.Equal(invoice.PaymentHash[:], serverPaymentHash) { - return errors.Errorf("payment hash doesn't match %v != %v", invoice.PaymentHash, swap.FundingOutput().ServerPaymentHashInHex()) - } - - // TODO: check that timelock is acceptable - - // Validate that the refund address is one we can derive - - swapRefundAddress := swap.FundingOutput().UserRefundAddress() - derivedUserKey, err := userPublicKey.DeriveTo(swapRefundAddress.DerivationPath()) - if err != nil { - return errors.Wrapf(err, "failed to derive user key") - } - derivedMuunKey, err := muunPublicKey.DeriveTo(swapRefundAddress.DerivationPath()) - if err != nil { - return errors.Wrapf(err, "failed to derive muun key") - } - - refundAddress, err := newMuunAddress(AddressVersion(swapRefundAddress.Version()), derivedUserKey, derivedMuunKey) - if err != nil { - return errors.Wrapf(err, "failed to generate refund address") - } - - if refundAddress.Address() != swapRefundAddress.Address() { - return errors.Errorf("refund address doesn't match generated (%v != %v)", swapRefundAddress.Address(), refundAddress.Address()) - } - - // Check the swap's witness script is a valid swap script - - serverPubKey, err := hex.DecodeString(swap.FundingOutput().ServerPublicKeyInHex()) - if err != nil { - return errors.Wrapf(err, "server pub key is not hex") - } - - witnessScript, err := createWitnessScriptSubmarineSwap( - swapRefundAddress.Address(), - serverPaymentHash, - serverPubKey, - swap.FundingOutput().UserLockTime(), - network) - if err != nil { - return errors.Wrapf(err, "failed to compute witness script") - } - - redeemScript, err := createNonNativeSegwitRedeemScript(witnessScript) - if err != nil { - return errors.Wrapf(err, "failed to build redeem script") - } - - address, err := btcutil.NewAddressScriptHash(redeemScript, network.network) - if err != nil { - return errors.Wrapf(err, "failed to build address for swap script") - } - - if address.EncodeAddress() != swap.FundingOutput().OutputAddress() { - return errors.Errorf("address for swap script mismatch (%v != %v)", address.EncodeAddress(), swap.FundingOutput().OutputAddress()) - } - - if len(swap.PreimageInHex()) > 0 { - preimage, err := hex.DecodeString(swap.PreimageInHex()) - if err != nil { - return errors.Wrapf(err, "preimagehex is not actually hex 🤔") - } +func ValidateSubmarineSwap(rawInvoice string, userPublicKey *HDPublicKey, muunPublicKey *HDPublicKey, swap SubmarineSwap, originalExpirationInBlocks int64, network *Network) error { - calculatedPaymentHash := sha256.Sum256(preimage) - if !bytes.Equal(invoice.PaymentHash[:], calculatedPaymentHash[:]) { - return errors.Errorf("payment hash doesn't match preimage (%v != hash(%v)", invoice.PaymentHash, swap.PreimageInHex()) - } + switch AddressVersion(swap.FundingOutput().ScriptVersion()) { + case addressSubmarineSwapV1: + return ValidateSubmarineSwapV1(rawInvoice, userPublicKey, muunPublicKey, swap, network) + case addressSubmarineSwapV2: + return ValidateSubmarineSwapV2(rawInvoice, userPublicKey, muunPublicKey, swap, originalExpirationInBlocks, network) } - return nil + return errors.Errorf("unknown swap version %v", swap.FundingOutput().ScriptVersion()) } diff --git a/submarineSwapV1.go b/submarineSwapV1.go new file mode 100644 index 0000000..6ea9fba --- /dev/null +++ b/submarineSwapV1.go @@ -0,0 +1,180 @@ +package libwallet + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + + "github.com/btcsuite/btcd/txscript" + "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcutil" + "github.com/pkg/errors" +) + +func addUserSignatureInputSubmarineSwapV1(input Input, index int, tx *wire.MsgTx, privateKey *HDPrivateKey, + muunKey *HDPublicKey) (*wire.TxIn, error) { + + submarineSwap := input.SubmarineSwapV1() + if submarineSwap == nil { + return nil, errors.Errorf("submarine swap data is nil for ss input") + } + + witnessScript, err := createWitnessScriptSubmarineSwapV1(submarineSwap.RefundAddress(), + submarineSwap.PaymentHash256(), + submarineSwap.ServerPublicKey(), + submarineSwap.LockTime(), + privateKey.Network) + if err != nil { + return nil, err + } + + redeemScript, err := createNonNativeSegwitRedeemScript(witnessScript) + if err != nil { + return nil, errors.Wrapf(err, "failed to build reedem script for signing") + } + + sig, err := signNonNativeSegwitInput(input, index, tx, privateKey, redeemScript, witnessScript) + if err != nil { + return nil, err + } + + txInput := tx.TxIn[index] + txInput.Witness = wire.TxWitness{sig, privateKey.PublicKey().Raw(), witnessScript} + + return txInput, nil +} + +//lint:ignore U1000 unused function for consistency with other schemes +func createRedeemScriptSubmarineSwapForUser(publicKey *HDPublicKey) { + +} + +func createWitnessScriptSubmarineSwapV1(refundAddress string, paymentHash []byte, swapServerPubKey []byte, lockTime int64, network *Network) ([]byte, error) { + + // It turns out that the payment hash present in an invoice is just the SHA256 of the + // payment preimage, so we still have to do a pass of RIPEMD160 before pushing it to the + // script + paymentHash160 := ripemd160(paymentHash) + decodedRefundAddress, err := btcutil.DecodeAddress(refundAddress, network.network) + if err != nil { + return nil, errors.Wrapf(err, "refund address is invalid") + } + + refundAddressHash := decodedRefundAddress.ScriptAddress() + + builder := txscript.NewScriptBuilder() + builder.AddOp(txscript.OP_DUP) + + // Condition to decide which branch to follow: + builder.AddOp(txscript.OP_HASH160). + AddData(paymentHash160). + AddOp(txscript.OP_EQUAL) + + // SubmarineSwap service spending script, for successful LN payments: + builder.AddOp(txscript.OP_IF). + AddOp(txscript.OP_DROP). + AddData(swapServerPubKey) + + // User spending script, for failed LN payments: + builder.AddOp(txscript.OP_ELSE). + AddInt64(lockTime). + AddOp(txscript.OP_CHECKLOCKTIMEVERIFY). + AddOp(txscript.OP_DROP). + AddOp(txscript.OP_DUP). + AddOp(txscript.OP_HASH160). + AddData(refundAddressHash). + AddOp(txscript.OP_EQUALVERIFY) + + // Final verification for both branches: + builder.AddOp(txscript.OP_ENDIF). + AddOp(txscript.OP_CHECKSIG) + + return builder.Script() +} + +func ValidateSubmarineSwapV1(rawInvoice string, userPublicKey *HDPublicKey, muunPublicKey *HDPublicKey, swap SubmarineSwap, network *Network) error { + + invoice, err := ParseInvoice(rawInvoice, network) + if err != nil { + return errors.Wrapf(err, "failed to decode invoice") + } + + // Check the payment hash matches + + serverPaymentHash, err := hex.DecodeString(swap.FundingOutput().ServerPaymentHashInHex()) + if err != nil { + return errors.Wrapf(err, "server payment hash is not valid hex") + } + + if !bytes.Equal(invoice.PaymentHash[:], serverPaymentHash) { + return errors.Errorf("payment hash doesn't match %v != %v", invoice.PaymentHash, swap.FundingOutput().ServerPaymentHashInHex()) + } + + // TODO: check that timelock is acceptable + + // Validate that the refund address is one we can derive + + swapRefundAddress := swap.FundingOutput().UserRefundAddress() + derivedUserKey, err := userPublicKey.DeriveTo(swapRefundAddress.DerivationPath()) + if err != nil { + return errors.Wrapf(err, "failed to derive user key") + } + derivedMuunKey, err := muunPublicKey.DeriveTo(swapRefundAddress.DerivationPath()) + if err != nil { + return errors.Wrapf(err, "failed to derive muun key") + } + + refundAddress, err := newMuunAddress(AddressVersion(swapRefundAddress.Version()), derivedUserKey, derivedMuunKey) + if err != nil { + return errors.Wrapf(err, "failed to generate refund address") + } + + if refundAddress.Address() != swapRefundAddress.Address() { + return errors.Errorf("refund address doesn't match generated (%v != %v)", swapRefundAddress.Address(), refundAddress.Address()) + } + + // Check the swap's witness script is a valid swap script + + serverPubKey, err := hex.DecodeString(swap.FundingOutput().ServerPublicKeyInHex()) + if err != nil { + return errors.Wrapf(err, "server pub key is not hex") + } + + witnessScript, err := createWitnessScriptSubmarineSwapV1( + swapRefundAddress.Address(), + serverPaymentHash, + serverPubKey, + swap.FundingOutput().UserLockTime(), + network) + if err != nil { + return errors.Wrapf(err, "failed to compute witness script") + } + + redeemScript, err := createNonNativeSegwitRedeemScript(witnessScript) + if err != nil { + return errors.Wrapf(err, "failed to build redeem script") + } + + address, err := btcutil.NewAddressScriptHash(redeemScript, network.network) + if err != nil { + return errors.Wrapf(err, "failed to build address for swap script") + } + + if address.EncodeAddress() != swap.FundingOutput().OutputAddress() { + return errors.Errorf("address for swap script mismatch (%v != %v)", address.EncodeAddress(), swap.FundingOutput().OutputAddress()) + } + + if len(swap.PreimageInHex()) > 0 { + preimage, err := hex.DecodeString(swap.PreimageInHex()) + if err != nil { + return errors.Wrapf(err, "preimagehex is not actually hex 🤔") + } + + calculatedPaymentHash := sha256.Sum256(preimage) + if !bytes.Equal(invoice.PaymentHash[:], calculatedPaymentHash[:]) { + return errors.Errorf("payment hash doesn't match preimage (%v != hash(%v)", invoice.PaymentHash, swap.PreimageInHex()) + } + } + + return nil +} diff --git a/submarineSwapV1_test.go b/submarineSwapV1_test.go new file mode 100644 index 0000000..54aece9 --- /dev/null +++ b/submarineSwapV1_test.go @@ -0,0 +1,27 @@ +package libwallet + +import "testing" + +func TestValidateSubmarineSwap(t *testing.T) { + type args struct { + rawInvoice string + userPublicKey *HDPublicKey + muunPublicKey *HDPublicKey + swap SubmarineSwap + network *Network + } + tests := []struct { + name string + args args + wantErr bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := ValidateSubmarineSwapV1(tt.args.rawInvoice, tt.args.userPublicKey, tt.args.muunPublicKey, tt.args.swap, tt.args.network); (err != nil) != tt.wantErr { + t.Errorf("ValidateSubmarineSwapV1() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/submarineSwapV2.go b/submarineSwapV2.go new file mode 100644 index 0000000..658fb40 --- /dev/null +++ b/submarineSwapV2.go @@ -0,0 +1,231 @@ +package libwallet + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + + "github.com/btcsuite/btcd/txscript" + "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcutil" + "github.com/pkg/errors" +) + +func addUserSignatureInputSubmarineSwapV2(input Input, index int, tx *wire.MsgTx, privateKey *HDPrivateKey, + muunKey *HDPublicKey) (*wire.TxIn, error) { + + submarineSwap := input.SubmarineSwapV2() + if submarineSwap == nil { + return nil, errors.Errorf("submarine swap data is nil for ss input") + } + + if len(submarineSwap.ServerSignature()) == 0 { + return nil, errors.Errorf("Swap server must provide signature") + } + + witnessScript, err := createWitnessScriptSubmarineSwapV2( + submarineSwap.PaymentHash256(), + submarineSwap.UserPublicKey(), + submarineSwap.MuunPublicKey(), + submarineSwap.ServerPublicKey(), + submarineSwap.BlocksForExpiration()) + if err != nil { + return nil, err + } + + sig, err := signNativeSegwitInput(input, index, tx, privateKey, witnessScript) + if err != nil { + return nil, err + } + + txInput := tx.TxIn[index] + txInput.Witness = wire.TxWitness{ + sig, + submarineSwap.ServerSignature(), + witnessScript, + } + + return txInput, nil +} + +func createWitnessScriptSubmarineSwapV2(paymentHash, userPubKey, muunPubKey, swapServerPubKey []byte, blocksForExpiration int64) ([]byte, error) { + + // It turns out that the payment hash present in an invoice is just the SHA256 of the + // payment preimage, so we still have to do a pass of RIPEMD160 before pushing it to the + // script + paymentHash160 := ripemd160(paymentHash) + muunPublicKeyHash160 := btcutil.Hash160(muunPubKey) + + // Equivalent miniscript (http://bitcoin.sipa.be/miniscript/): + // or( + // and(pk(userPublicKey), pk(swapServerPublicKey)), + // or( + // and(pk(swapServerPublicKey), hash160(swapPaymentHash160)), + // and(pk(userPublicKey), and(pk(muunPublicKey), older(numBlocksForExpiration))) + // ) + // ) + // + // However, we differ in that the size of the script was heavily optimized for spending the + // first two branches (the collaborative close and the unilateral close by swapper), which + // are the most probable to be used. + + builder := txscript.NewScriptBuilder(). + // Push the user public key to the second position of the stack + AddData(userPubKey). + AddOp(txscript.OP_SWAP). + + // Check whether the first stack item was a valid swap server signature + AddData(swapServerPubKey). + AddOp(txscript.OP_CHECKSIG). + + // If the swap server signature was correct + AddOp(txscript.OP_IF). + AddOp(txscript.OP_SWAP). + + // Check whether the second stack item was the payment preimage + AddOp(txscript.OP_DUP). + AddOp(txscript.OP_HASH160). + AddData(paymentHash160). + AddOp(txscript.OP_EQUAL). + + // If the preimage was correct + AddOp(txscript.OP_IF). + // We are done, leave just one true-ish item in the stack (there're 2 + // remaining items) + AddOp(txscript.OP_DROP). + + // If the second stack item wasn't a valid payment preimage + AddOp(txscript.OP_ELSE). + + // Validate that the second stack item was a valid user signature + AddOp(txscript.OP_SWAP). + AddOp(txscript.OP_CHECKSIG). + AddOp(txscript.OP_ENDIF). + + // If the first stack item wasn't a valid server signature + AddOp(txscript.OP_ELSE). + // Validate that the blockchain height is big enough + AddInt64(blocksForExpiration). + AddOp(txscript.OP_CHECKSEQUENCEVERIFY). + AddOp(txscript.OP_DROP). + + // Validate that the second stack item was a valid user signature + AddOp(txscript.OP_CHECKSIGVERIFY). + + // Validate that the third stack item was the muun public key + AddOp(txscript.OP_DUP). + AddOp(txscript.OP_HASH160). + AddData(muunPublicKeyHash160). + AddOp(txscript.OP_EQUALVERIFY). + + // Notice that instead of directly pushing the public key here and checking the + // signature P2PK-style, we pushed the hash of the public key, and require an + // extra stack item with the actual public key, verifying the signature and + // public key P2PKH-style. + // + // This trick reduces the on-chain footprint of the muun key from 33 bytes to + // 20 bytes for the collaborative, and swap server's non-collaborative branches, + // which are the most frequent ones. + + // Validate that the fourth stack item was a valid server signature + AddOp(txscript.OP_CHECKSIG). + AddOp(txscript.OP_ENDIF) + + return builder.Script() +} + +func ValidateSubmarineSwapV2(rawInvoice string, userPublicKey *HDPublicKey, muunPublicKey *HDPublicKey, swap SubmarineSwap, originalExpirationInBlocks int64, network *Network) error { + + fundingOutput := swap.FundingOutput() + + invoice, err := ParseInvoice(rawInvoice, network) + if err != nil { + return errors.Wrapf(err, "failed to decode invoice") + } + + // Check the payment hash matches + + serverPaymentHash, err := hex.DecodeString(fundingOutput.ServerPaymentHashInHex()) + if err != nil { + return errors.Wrapf(err, "server payment hash is not valid hex") + } + + if !bytes.Equal(invoice.PaymentHash[:], serverPaymentHash) { + return errors.Errorf("payment hash doesn't match %v != %v", invoice.PaymentHash, fundingOutput.ServerPaymentHashInHex()) + } + + destination, err := hex.DecodeString(swap.Receiver().PublicKey()) + if err != nil { + return errors.Wrapf(err, "destination is not valid hex") + } + + if !bytes.Equal(invoice.Destination[:], destination) { + return errors.Errorf("destination doesnt match %v != %v", invoice.Destination, swap.Receiver().PublicKey()) + } + + if fundingOutput.ExpirationInBlocks() != originalExpirationInBlocks { + return errors.Errorf("expiration in blocks doesnt match %v != %v", originalExpirationInBlocks, fundingOutput.ExpirationInBlocks()) + } + + // Validate that we can derive the addresses involved + derivationPath := fundingOutput.UserPublicKey().Path + + derivedUserKey, err := userPublicKey.DeriveTo(derivationPath) + if err != nil { + return errors.Wrapf(err, "failed to derive user key") + } + + if !bytes.Equal(derivedUserKey.Raw(), fundingOutput.UserPublicKey().Raw()) { + return errors.Errorf("user pub keys dont match %v != %v", derivedUserKey.String(), fundingOutput.UserPublicKey().String()) + } + + derivedMuunKey, err := muunPublicKey.DeriveTo(derivationPath) + if err != nil { + return errors.Wrapf(err, "failed to derive muun key") + } + + if !bytes.Equal(derivedMuunKey.Raw(), fundingOutput.MuunPublicKey().Raw()) { + return errors.Errorf("muun pub keys dont match %v != %v", derivedMuunKey.String(), fundingOutput.MuunPublicKey().String()) + } + + // Check the swap's witness script is a valid swap script + + serverPubKey, err := hex.DecodeString(swap.FundingOutput().ServerPublicKeyInHex()) + if err != nil { + return errors.Wrapf(err, "server pub key is not hex") + } + + witnessScript, err := createWitnessScriptSubmarineSwapV2( + serverPaymentHash, + derivedUserKey.Raw(), + derivedMuunKey.Raw(), + serverPubKey, + swap.FundingOutput().ExpirationInBlocks()) + if err != nil { + return errors.Wrapf(err, "failed to compute witness script") + } + + witnessScriptHash := sha256.Sum256(witnessScript) + address, err := btcutil.NewAddressWitnessScriptHash(witnessScriptHash[:], network.network) + if err != nil { + return errors.Wrapf(err, "failed to build address for swap script") + } + + if address.EncodeAddress() != swap.FundingOutput().OutputAddress() { + return errors.Errorf("address for swap script mismatch (%v != %v)", address.EncodeAddress(), swap.FundingOutput().OutputAddress()) + } + + if len(swap.PreimageInHex()) > 0 { + preimage, err := hex.DecodeString(swap.PreimageInHex()) + if err != nil { + return errors.Wrapf(err, "preimagehex is not actually hex 🤔") + } + + calculatedPaymentHash := sha256.Sum256(preimage) + if !bytes.Equal(invoice.PaymentHash[:], calculatedPaymentHash[:]) { + return errors.Errorf("payment hash doesn't match preimage (%v != hash(%v)", invoice.PaymentHash, swap.PreimageInHex()) + } + } + + return nil +} diff --git a/vendor/github.com/btcsuite/btcd/btcec/btcec.go b/vendor/github.com/btcsuite/btcd/btcec/btcec.go index 5e7ce87..de93a25 100644 --- a/vendor/github.com/btcsuite/btcd/btcec/btcec.go +++ b/vendor/github.com/btcsuite/btcd/btcec/btcec.go @@ -36,10 +36,17 @@ var ( // interface from crypto/elliptic. type KoblitzCurve struct { *elliptic.CurveParams - q *big.Int + + // q is the value (P+1)/4 used to compute the square root of field + // elements. + q *big.Int + H int // cofactor of the curve. halfOrder *big.Int // half the order N + // fieldB is the constant B of the curve as a fieldVal. + fieldB *fieldVal + // byteSize is simply the bit size / 8 and is provided for convenience // since it is calculated repeatedly. byteSize int @@ -879,12 +886,22 @@ func (curve *KoblitzCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { return curve.fieldJacobianToBigAffine(qx, qy, qz) } -// QPlus1Div4 returns the Q+1/4 constant for the curve for use in calculating -// square roots via exponention. +// QPlus1Div4 returns the (P+1)/4 constant for the curve for use in calculating +// square roots via exponentiation. +// +// DEPRECATED: The actual value returned is (P+1)/4, where as the original +// method name implies that this value is (((P+1)/4)+1)/4. This method is kept +// to maintain backwards compatibility of the API. Use Q() instead. func (curve *KoblitzCurve) QPlus1Div4() *big.Int { return curve.q } +// Q returns the (P+1)/4 constant for the curve for use in calculating square +// roots via exponentiation. +func (curve *KoblitzCurve) Q() *big.Int { + return curve.q +} + var initonce sync.Once var secp256k1 KoblitzCurve @@ -917,6 +934,7 @@ func initS256() { big.NewInt(1)), big.NewInt(4)) secp256k1.H = 1 secp256k1.halfOrder = new(big.Int).Rsh(secp256k1.N, 1) + secp256k1.fieldB = new(fieldVal).SetByteSlice(secp256k1.B.Bytes()) // Provided for convenience since this gets computed repeatedly. secp256k1.byteSize = secp256k1.BitSize / 8 diff --git a/vendor/github.com/btcsuite/btcd/btcec/field.go b/vendor/github.com/btcsuite/btcd/btcec/field.go index 0f2be74..c2bb84b 100644 --- a/vendor/github.com/btcsuite/btcd/btcec/field.go +++ b/vendor/github.com/btcsuite/btcd/btcec/field.go @@ -102,6 +102,20 @@ const ( fieldPrimeWordOne = 0x3ffffbf ) +var ( + // fieldQBytes is the value Q = (P+1)/4 for the secp256k1 prime P. This + // value is used to efficiently compute the square root of values in the + // field via exponentiation. The value of Q in hex is: + // + // Q = 3fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff0c + fieldQBytes = []byte{ + 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0x0c, + } +) + // fieldVal implements optimized fixed-precision arithmetic over the // secp256k1 finite field. This means all arithmetic is performed modulo // 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f. It @@ -1221,3 +1235,118 @@ func (f *fieldVal) Inverse() *fieldVal { f.Square().Square().Square().Square().Square() // f = a^(2^256 - 4294968320) return f.Mul(&a45) // f = a^(2^256 - 4294968275) = a^(p-2) } + +// SqrtVal computes the square root of x modulo the curve's prime, and stores +// the result in f. The square root is computed via exponentiation of x by the +// value Q = (P+1)/4 using the curve's precomputed big-endian representation of +// the Q. This method uses a modified version of square-and-multiply +// exponentiation over secp256k1 fieldVals to operate on bytes instead of bits, +// which offers better performance over both big.Int exponentiation and bit-wise +// square-and-multiply. +// +// NOTE: This method only works when P is intended to be the secp256k1 prime and +// is not constant time. The returned value is of magnitude 1, but is +// denormalized. +func (f *fieldVal) SqrtVal(x *fieldVal) *fieldVal { + // The following computation iteratively computes x^((P+1)/4) = x^Q + // using the recursive, piece-wise definition: + // + // x^n = (x^2)^(n/2) mod P if n is even + // x^n = x(x^2)^(n-1/2) mod P if n is odd + // + // Given n in its big-endian representation b_k, ..., b_0, x^n can be + // computed by defining the sequence r_k+1, ..., r_0, where: + // + // r_k+1 = 1 + // r_i = (r_i+1)^2 * x^b_i for i = k, ..., 0 + // + // The final value r_0 = x^n. + // + // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more + // details. + // + // This can be further optimized, by observing that the value of Q in + // secp256k1 has the value: + // + // Q = 3fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff0c + // + // We can unroll the typical bit-wise interpretation of the + // exponentiation algorithm above to instead operate on bytes. + // This reduces the number of comparisons by an order of magnitude, + // reducing the overhead of failed branch predictions and additional + // comparisons in this method. + // + // Since there there are only 4 unique bytes of Q, this keeps the jump + // table small without the need to handle all possible 8-bit values. + // Further, we observe that 29 of the 32 bytes are 0xff; making the + // first case handle 0xff therefore optimizes the hot path. + f.SetInt(1) + for _, b := range fieldQBytes { + switch b { + + // Most common case, where all 8 bits are set. + case 0xff: + f.Square().Mul(x) + f.Square().Mul(x) + f.Square().Mul(x) + f.Square().Mul(x) + f.Square().Mul(x) + f.Square().Mul(x) + f.Square().Mul(x) + f.Square().Mul(x) + + // First byte of Q (0x3f), where all but the top two bits are + // set. Note that this case only applies six operations, since + // the highest bit of Q resides in bit six of the first byte. We + // ignore the first two bits, since squaring for these bits will + // result in an invalid result. We forgo squaring f before the + // first multiply, since 1^2 = 1. + case 0x3f: + f.Mul(x) + f.Square().Mul(x) + f.Square().Mul(x) + f.Square().Mul(x) + f.Square().Mul(x) + f.Square().Mul(x) + + // Byte 28 of Q (0xbf), where only bit 7 is unset. + case 0xbf: + f.Square().Mul(x) + f.Square() + f.Square().Mul(x) + f.Square().Mul(x) + f.Square().Mul(x) + f.Square().Mul(x) + f.Square().Mul(x) + f.Square().Mul(x) + + // Byte 31 of Q (0x0c), where only bits 3 and 4 are set. + default: + f.Square() + f.Square() + f.Square() + f.Square() + f.Square().Mul(x) + f.Square().Mul(x) + f.Square() + f.Square() + } + } + + return f +} + +// Sqrt computes the square root of f modulo the curve's prime, and stores the +// result in f. The square root is computed via exponentiation of x by the value +// Q = (P+1)/4 using the curve's precomputed big-endian representation of the Q. +// This method uses a modified version of square-and-multiply exponentiation +// over secp256k1 fieldVals to operate on bytes instead of bits, which offers +// better performance over both big.Int exponentiation and bit-wise +// square-and-multiply. +// +// NOTE: This method only works when P is intended to be the secp256k1 prime and +// is not constant time. The returned value is of magnitude 1, but is +// denormalized. +func (f *fieldVal) Sqrt() *fieldVal { + return f.SqrtVal(f) +} diff --git a/vendor/github.com/btcsuite/btcd/btcec/genprecomps.go b/vendor/github.com/btcsuite/btcd/btcec/genprecomps.go deleted file mode 100644 index d4a9c1b..0000000 --- a/vendor/github.com/btcsuite/btcd/btcec/genprecomps.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2015 The btcsuite developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -// This file is ignored during the regular build due to the following build tag. -// It is called by go generate and used to automatically generate pre-computed -// tables used to accelerate operations. -// +build ignore - -package main - -import ( - "bytes" - "compress/zlib" - "encoding/base64" - "fmt" - "log" - "os" - - "github.com/btcsuite/btcd/btcec" -) - -func main() { - fi, err := os.Create("secp256k1.go") - if err != nil { - log.Fatal(err) - } - defer fi.Close() - - // Compress the serialized byte points. - serialized := btcec.S256().SerializedBytePoints() - var compressed bytes.Buffer - w := zlib.NewWriter(&compressed) - if _, err := w.Write(serialized); err != nil { - fmt.Println(err) - os.Exit(1) - } - w.Close() - - // Encode the compressed byte points with base64. - encoded := make([]byte, base64.StdEncoding.EncodedLen(compressed.Len())) - base64.StdEncoding.Encode(encoded, compressed.Bytes()) - - fmt.Fprintln(fi, "// Copyright (c) 2015 The btcsuite developers") - fmt.Fprintln(fi, "// Use of this source code is governed by an ISC") - fmt.Fprintln(fi, "// license that can be found in the LICENSE file.") - fmt.Fprintln(fi) - fmt.Fprintln(fi, "package btcec") - fmt.Fprintln(fi) - fmt.Fprintln(fi, "// Auto-generated file (see genprecomps.go)") - fmt.Fprintln(fi, "// DO NOT EDIT") - fmt.Fprintln(fi) - fmt.Fprintf(fi, "var secp256k1BytePoints = %q\n", string(encoded)) - - a1, b1, a2, b2 := btcec.S256().EndomorphismVectors() - fmt.Println("The following values are the computed linearly " + - "independent vectors needed to make use of the secp256k1 " + - "endomorphism:") - fmt.Printf("a1: %x\n", a1) - fmt.Printf("b1: %x\n", b1) - fmt.Printf("a2: %x\n", a2) - fmt.Printf("b2: %x\n", b2) -} diff --git a/vendor/github.com/btcsuite/btcd/btcec/pubkey.go b/vendor/github.com/btcsuite/btcd/btcec/pubkey.go index cf49807..3c9d5d0 100644 --- a/vendor/github.com/btcsuite/btcd/btcec/pubkey.go +++ b/vendor/github.com/btcsuite/btcd/btcec/pubkey.go @@ -22,41 +22,40 @@ func isOdd(a *big.Int) bool { return a.Bit(0) == 1 } -// decompressPoint decompresses a point on the given curve given the X point and +// decompressPoint decompresses a point on the secp256k1 curve given the X point and // the solution to use. -func decompressPoint(curve *KoblitzCurve, x *big.Int, ybit bool) (*big.Int, error) { - // TODO: This will probably only work for secp256k1 due to - // optimizations. +func decompressPoint(curve *KoblitzCurve, bigX *big.Int, ybit bool) (*big.Int, error) { + var x fieldVal + x.SetByteSlice(bigX.Bytes()) - // Y = +-sqrt(x^3 + B) - x3 := new(big.Int).Mul(x, x) - x3.Mul(x3, x) - x3.Add(x3, curve.Params().B) - x3.Mod(x3, curve.Params().P) + // Compute x^3 + B mod p. + var x3 fieldVal + x3.SquareVal(&x).Mul(&x) + x3.Add(curve.fieldB).Normalize() // Now calculate sqrt mod p of x^3 + B // This code used to do a full sqrt based on tonelli/shanks, // but this was replaced by the algorithms referenced in // https://bitcointalk.org/index.php?topic=162805.msg1712294#msg1712294 - y := new(big.Int).Exp(x3, curve.QPlus1Div4(), curve.Params().P) - - if ybit != isOdd(y) { - y.Sub(curve.Params().P, y) + var y fieldVal + y.SqrtVal(&x3).Normalize() + if ybit != y.IsOdd() { + y.Negate(1).Normalize() } // Check that y is a square root of x^3 + B. - y2 := new(big.Int).Mul(y, y) - y2.Mod(y2, curve.Params().P) - if y2.Cmp(x3) != 0 { + var y2 fieldVal + y2.SquareVal(&y).Normalize() + if !y2.Equals(&x3) { return nil, fmt.Errorf("invalid square root") } // Verify that y-coord has expected parity. - if ybit != isOdd(y) { + if ybit != y.IsOdd() { return nil, fmt.Errorf("ybit doesn't match oddness") } - return y, nil + return new(big.Int).SetBytes(y.Bytes()[:]), nil } const ( @@ -102,6 +101,17 @@ func ParsePubKey(pubKeyStr []byte, curve *KoblitzCurve) (key *PublicKey, err err if format == pubkeyHybrid && ybit != isOdd(pubkey.Y) { return nil, fmt.Errorf("ybit doesn't match oddness") } + + if pubkey.X.Cmp(pubkey.Curve.Params().P) >= 0 { + return nil, fmt.Errorf("pubkey X parameter is >= to P") + } + if pubkey.Y.Cmp(pubkey.Curve.Params().P) >= 0 { + return nil, fmt.Errorf("pubkey Y parameter is >= to P") + } + if !pubkey.Curve.IsOnCurve(pubkey.X, pubkey.Y) { + return nil, fmt.Errorf("pubkey isn't on secp256k1 curve") + } + case PubKeyBytesLenCompressed: // format is 0x2 | solution, // solution determines which solution of the curve we use. @@ -115,20 +125,12 @@ func ParsePubKey(pubKeyStr []byte, curve *KoblitzCurve) (key *PublicKey, err err if err != nil { return nil, err } + default: // wrong! return nil, fmt.Errorf("invalid pub key length %d", len(pubKeyStr)) } - if pubkey.X.Cmp(pubkey.Curve.Params().P) >= 0 { - return nil, fmt.Errorf("pubkey X parameter is >= to P") - } - if pubkey.Y.Cmp(pubkey.Curve.Params().P) >= 0 { - return nil, fmt.Errorf("pubkey Y parameter is >= to P") - } - if !pubkey.Curve.IsOnCurve(pubkey.X, pubkey.Y) { - return nil, fmt.Errorf("pubkey isn't on secp256k1 curve") - } return &pubkey, nil } diff --git a/vendor/github.com/btcsuite/btcd/btcec/signature.go b/vendor/github.com/btcsuite/btcd/btcec/signature.go index f1c4377..deedd17 100644 --- a/vendor/github.com/btcsuite/btcd/btcec/signature.go +++ b/vendor/github.com/btcsuite/btcd/btcec/signature.go @@ -276,7 +276,7 @@ func hashToInt(hash []byte, c elliptic.Curve) *big.Int { } // recoverKeyFromSignature recovers a public key from the signature "sig" on the -// given message hash "msg". Based on the algorithm found in section 5.1.5 of +// given message hash "msg". Based on the algorithm found in section 4.1.6 of // SEC 1 Ver 2.0, page 47-48 (53 and 54 in the pdf). This performs the details // in the inner loop in Step 1. The counter provided is actually the j parameter // of the loop * 2 - on the first iteration of j we do the R case, else the -R diff --git a/vendor/github.com/btcsuite/btcutil/base58/genalphabet.go b/vendor/github.com/btcsuite/btcutil/base58/genalphabet.go deleted file mode 100644 index 010cbee..0000000 --- a/vendor/github.com/btcsuite/btcutil/base58/genalphabet.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2015 The btcsuite developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -//+build ignore - -package main - -import ( - "bytes" - "io" - "log" - "os" - "strconv" -) - -var ( - start = []byte(`// Copyright (c) 2015 The btcsuite developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -// AUTOGENERATED by genalphabet.go; do not edit. - -package base58 - -const ( - // alphabet is the modified base58 alphabet used by Bitcoin. - alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" - - alphabetIdx0 = '1' -) - -var b58 = [256]byte{`) - - end = []byte(`}`) - - alphabet = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") - tab = []byte("\t") - invalid = []byte("255") - comma = []byte(",") - space = []byte(" ") - nl = []byte("\n") -) - -func write(w io.Writer, b []byte) { - _, err := w.Write(b) - if err != nil { - log.Fatal(err) - } -} - -func main() { - fi, err := os.Create("alphabet.go") - if err != nil { - log.Fatal(err) - } - defer fi.Close() - - write(fi, start) - write(fi, nl) - for i := byte(0); i < 32; i++ { - write(fi, tab) - for j := byte(0); j < 8; j++ { - idx := bytes.IndexByte(alphabet, i*8+j) - if idx == -1 { - write(fi, invalid) - } else { - write(fi, strconv.AppendInt(nil, int64(idx), 10)) - } - write(fi, comma) - if j != 7 { - write(fi, space) - } - } - write(fi, nl) - } - write(fi, end) - write(fi, nl) -} diff --git a/vendor/github.com/lightningnetwork/lnd/lnwire/commit_sig.go b/vendor/github.com/lightningnetwork/lnd/lnwire/commit_sig.go index 5002d5f..72c235b 100644 --- a/vendor/github.com/lightningnetwork/lnd/lnwire/commit_sig.go +++ b/vendor/github.com/lightningnetwork/lnd/lnwire/commit_sig.go @@ -1,6 +1,8 @@ package lnwire -import "io" +import ( + "io" +) // CommitSig is sent by either side to stage any pending HTLC's in the // receiver's pending set into a new commitment state. Implicitly, the new @@ -83,3 +85,11 @@ func (c *CommitSig) MaxPayloadLength(uint32) uint32 { // 32 + 64 + 2 + max_allowed_htlcs return MaxMessagePayload } + +// TargetChanID returns the channel id of the link for which this message is +// intended. +// +// NOTE: Part of lnd.LinkUpdater interface. +func (c *CommitSig) TargetChanID() ChannelID { + return c.ChanID +} diff --git a/vendor/github.com/lightningnetwork/lnd/lnwire/error.go b/vendor/github.com/lightningnetwork/lnd/lnwire/error.go index 5a4dd1b..c9fa39a 100644 --- a/vendor/github.com/lightningnetwork/lnd/lnwire/error.go +++ b/vendor/github.com/lightningnetwork/lnd/lnwire/error.go @@ -1,41 +1,32 @@ package lnwire import ( + "fmt" "io" - - "google.golang.org/grpc/codes" ) -// ErrorCode represents the short error code for each of the defined errors -// within the Lightning Network protocol spec. -type ErrorCode uint8 - -// ToGrpcCode is used to generate gRPC specific code which will be propagated -// to the ln rpc client. This code is used to have more detailed view of what -// goes wrong and also in order to have the ability pragmatically determine the -// error and take specific actions on the client side. -func (e ErrorCode) ToGrpcCode() codes.Code { - return (codes.Code)(e) + 100 -} +// FundingError represents a set of errors that can be encountered and sent +// during the funding workflow. +type FundingError uint8 const ( // ErrMaxPendingChannels is returned by remote peer when the number of // active pending channels exceeds their maximum policy limit. - ErrMaxPendingChannels ErrorCode = 1 + ErrMaxPendingChannels FundingError = 1 // ErrSynchronizingChain is returned by a remote peer that receives a // channel update or a funding request while their still syncing to the // latest state of the blockchain. - ErrSynchronizingChain ErrorCode = 2 + ErrSynchronizingChain FundingError = 2 // ErrChanTooLarge is returned by a remote peer that receives a // FundingOpen request for a channel that is above their current // soft-limit. - ErrChanTooLarge ErrorCode = 3 + ErrChanTooLarge FundingError = 3 ) -// String returns a human readable version of the target ErrorCode. -func (e ErrorCode) String() string { +// String returns a human readable version of the target FundingError. +func (e FundingError) String() string { switch e { case ErrMaxPendingChannels: return "Number of pending channels exceed maximum" @@ -48,10 +39,10 @@ func (e ErrorCode) String() string { } } -// Error returns the human redable version of the target ErrorCode. +// Error returns the human redable version of the target FundingError. // -// Satisfies the Error interface. -func (e ErrorCode) Error() string { +// NOTE: Satisfies the Error interface. +func (e FundingError) Error() string { return e.String() } @@ -65,8 +56,6 @@ type ErrorData []byte // format is purposefully general in order to allow expression of a wide array // of possible errors. Each Error message is directed at a particular open // channel referenced by ChannelPoint. -// -// TODO(roasbeef): remove the error code type Error struct { // ChanID references the active channel in which the error occurred // within. If the ChanID is all zeros, then this error applies to the @@ -87,6 +76,18 @@ func NewError() *Error { // interface. var _ Message = (*Error)(nil) +// Error returns the string representation to Error. +// +// NOTE: Satisfies the error interface. +func (c *Error) Error() string { + errMsg := "non-ascii data" + if isASCII(c.Data) { + errMsg = string(c.Data) + } + + return fmt.Sprintf("chan_id=%v, err=%v", c.ChanID, errMsg) +} + // Decode deserializes a serialized Error message stored in the passed // io.Reader observing the specified protocol version. // @@ -125,3 +126,14 @@ func (c *Error) MaxPayloadLength(uint32) uint32 { // 32 + 2 + 65501 return 65535 } + +// isASCII is a helper method that checks whether all bytes in `data` would be +// printable ASCII characters if interpreted as a string. +func isASCII(data []byte) bool { + for _, c := range data { + if c < 32 || c > 126 { + return false + } + } + return true +} diff --git a/vendor/github.com/lightningnetwork/lnd/lnwire/features.go b/vendor/github.com/lightningnetwork/lnd/lnwire/features.go index 1dd536b..9a34a63 100644 --- a/vendor/github.com/lightningnetwork/lnd/lnwire/features.go +++ b/vendor/github.com/lightningnetwork/lnd/lnwire/features.go @@ -46,6 +46,25 @@ const ( // efficient network view reconciliation. GossipQueriesOptional FeatureBit = 7 + // TLVOnionPayloadRequired is a feature bit that indicates a node is + // able to decode the new TLV information included in the onion packet. + TLVOnionPayloadRequired FeatureBit = 8 + + // TLVOnionPayloadRequired is an optional feature bit that indicates a + // node is able to decode the new TLV information included in the onion + // packet. + TLVOnionPayloadOptional FeatureBit = 9 + + // StaticRemoteKeyRequired is a required feature bit that signals that + // within one's commitment transaction, the key used for the remote + // party's non-delay output should not be tweaked. + StaticRemoteKeyRequired FeatureBit = 12 + + // StaticRemoteKeyOptional is an optional feature bit that signals that + // within one's commitment transaction, the key used for the remote + // party's non-delay output should not be tweaked. + StaticRemoteKeyOptional FeatureBit = 13 + // maxAllowedSize is a maximum allowed size of feature vector. // // NOTE: Within the protocol, the maximum allowed message size is 65535 @@ -76,7 +95,12 @@ var LocalFeatures = map[FeatureBit]string{ // name. All known global feature bits must be assigned a name in this mapping. // Global features are those which are advertised to the entire network. A full // description of these feature bits is provided in the BOLT-09 specification. -var GlobalFeatures map[FeatureBit]string +var GlobalFeatures = map[FeatureBit]string{ + TLVOnionPayloadRequired: "tlv-onion", + TLVOnionPayloadOptional: "tlv-onion", + StaticRemoteKeyOptional: "static-remote-key", + StaticRemoteKeyRequired: "static-remote-key", +} // RawFeatureVector represents a set of feature bits as defined in BOLT-09. A // RawFeatureVector itself just stores a set of bit flags but can be used to @@ -115,6 +139,20 @@ func (fv *RawFeatureVector) Unset(feature FeatureBit) { // SerializeSize returns the number of bytes needed to represent feature vector // in byte format. func (fv *RawFeatureVector) SerializeSize() int { + // We calculate byte-length via the largest bit index. + return fv.serializeSize(8) +} + +// SerializeSize32 returns the number of bytes needed to represent feature +// vector in base32 format. +func (fv *RawFeatureVector) SerializeSize32() int { + // We calculate base32-length via the largest bit index. + return fv.serializeSize(5) +} + +// serializeSize returns the number of bytes required to encode the feature +// vector using at most width bits per encoded byte. +func (fv *RawFeatureVector) serializeSize(width int) int { // Find the largest feature bit index max := -1 for feature := range fv.features { @@ -127,8 +165,7 @@ func (fv *RawFeatureVector) SerializeSize() int { return 0 } - // We calculate byte-length via the largest bit index - return max/8 + 1 + return max/width + 1 } // Encode writes the feature vector in byte representation. Every feature @@ -144,12 +181,25 @@ func (fv *RawFeatureVector) Encode(w io.Writer) error { return err } + return fv.encode(w, length, 8) +} + +// EncodeBase32 writes the feature vector in base32 representation. Every feature +// encoded as a bit, and the bit vector is serialized using the least number of +// bytes. +func (fv *RawFeatureVector) EncodeBase32(w io.Writer) error { + length := fv.SerializeSize32() + return fv.encode(w, length, 5) +} + +// encode writes the feature vector +func (fv *RawFeatureVector) encode(w io.Writer, length, width int) error { // Generate the data and write it. data := make([]byte, length) for feature := range fv.features { - byteIndex := int(feature / 8) - bitIndex := feature % 8 - data[length-byteIndex-1] |= 1 << bitIndex + byteIndex := int(feature) / width + bitIndex := int(feature) % width + data[length-byteIndex-1] |= 1 << uint(bitIndex) } _, err := w.Write(data) @@ -168,6 +218,19 @@ func (fv *RawFeatureVector) Decode(r io.Reader) error { } length := binary.BigEndian.Uint16(l[:]) + return fv.decode(r, int(length), 8) +} + +// DecodeBase32 reads the feature vector from its base32 representation. Every +// feature encoded as a bit, and the bit vector is serialized using the least +// number of bytes. +func (fv *RawFeatureVector) DecodeBase32(r io.Reader, length int) error { + return fv.decode(r, length, 5) +} + +// decode reads a feature vector from the next length bytes of the io.Reader, +// assuming each byte has width feature bits encoded per byte. +func (fv *RawFeatureVector) decode(r io.Reader, length, width int) error { // Read the feature vector data. data := make([]byte, length) if _, err := io.ReadFull(r, data); err != nil { @@ -175,10 +238,10 @@ func (fv *RawFeatureVector) Decode(r io.Reader) error { } // Set feature bits from parsed data. - bitsNumber := len(data) * 8 + bitsNumber := len(data) * width for i := 0; i < bitsNumber; i++ { - byteIndex := uint16(i / 8) - bitIndex := uint(i % 8) + byteIndex := int(i / width) + bitIndex := uint(i % width) if (data[length-byteIndex-1]>>bitIndex)&1 == 1 { fv.Set(FeatureBit(i)) } diff --git a/vendor/github.com/lightningnetwork/lnd/lnwire/lnwire.go b/vendor/github.com/lightningnetwork/lnd/lnwire/lnwire.go index 28dca7d..e1f6a7d 100644 --- a/vendor/github.com/lightningnetwork/lnd/lnwire/lnwire.go +++ b/vendor/github.com/lightningnetwork/lnd/lnwire/lnwire.go @@ -117,12 +117,6 @@ func WriteElement(w io.Writer, element interface{}) error { if _, err := w.Write(b[:]); err != nil { return err } - case ErrorCode: - var b [2]byte - binary.BigEndian.PutUint16(b[:], uint16(e)) - if _, err := w.Write(b[:]); err != nil { - return err - } case MilliSatoshi: var b [8]byte binary.BigEndian.PutUint64(b[:], uint64(e)) @@ -506,12 +500,6 @@ func ReadElement(r io.Reader, element interface{}) error { return err } *e = ChanUpdateChanFlags(b[0]) - case *ErrorCode: - var b [2]byte - if _, err := io.ReadFull(r, b[:]); err != nil { - return err - } - *e = ErrorCode(binary.BigEndian.Uint16(b[:])) case *uint32: var b [4]byte if _, err := io.ReadFull(r, b[:]); err != nil { diff --git a/vendor/github.com/lightningnetwork/lnd/lnwire/node_announcement.go b/vendor/github.com/lightningnetwork/lnd/lnwire/node_announcement.go index 42c1d5e..4ea64fa 100644 --- a/vendor/github.com/lightningnetwork/lnd/lnwire/node_announcement.go +++ b/vendor/github.com/lightningnetwork/lnd/lnwire/node_announcement.go @@ -10,11 +10,6 @@ import ( "unicode/utf8" ) -var ( - startPort uint16 = 1024 - endPort uint16 = 49151 -) - // ErrUnknownAddrType is an error returned if we encounter an unknown address type // when parsing addresses. type ErrUnknownAddrType struct { diff --git a/vendor/github.com/lightningnetwork/lnd/lnwire/onion_error.go b/vendor/github.com/lightningnetwork/lnd/lnwire/onion_error.go index 6ea01d5..bf75b63 100644 --- a/vendor/github.com/lightningnetwork/lnd/lnwire/onion_error.go +++ b/vendor/github.com/lightningnetwork/lnd/lnwire/onion_error.go @@ -46,7 +46,7 @@ const ( FlagUpdate FailCode = 0x1000 ) -// FailCode specifies the precise reason that an upstream HTLC was cancelled. +// FailCode specifies the precise reason that an upstream HTLC was canceled. // Each UpdateFailHTLC message carries a FailCode which is to be passed // backwards, encrypted at each step back to the source of the HTLC within the // route. @@ -55,29 +55,29 @@ type FailCode uint16 // The currently defined onion failure types within this current version of the // Lightning protocol. const ( - CodeNone FailCode = 0 - CodeInvalidRealm = FlagBadOnion | 1 - CodeTemporaryNodeFailure = FlagNode | 2 - CodePermanentNodeFailure = FlagPerm | FlagNode | 2 - CodeRequiredNodeFeatureMissing = FlagPerm | FlagNode | 3 - CodeInvalidOnionVersion = FlagBadOnion | FlagPerm | 4 - CodeInvalidOnionHmac = FlagBadOnion | FlagPerm | 5 - CodeInvalidOnionKey = FlagBadOnion | FlagPerm | 6 - CodeTemporaryChannelFailure = FlagUpdate | 7 - CodePermanentChannelFailure = FlagPerm | 8 - CodeRequiredChannelFeatureMissing = FlagPerm | 9 - CodeUnknownNextPeer = FlagPerm | 10 - CodeAmountBelowMinimum = FlagUpdate | 11 - CodeFeeInsufficient = FlagUpdate | 12 - CodeIncorrectCltvExpiry = FlagUpdate | 13 - CodeExpiryTooSoon = FlagUpdate | 14 - CodeChannelDisabled = FlagUpdate | 20 - CodeUnknownPaymentHash = FlagPerm | 15 - CodeIncorrectPaymentAmount = FlagPerm | 16 - CodeFinalExpiryTooSoon FailCode = 17 - CodeFinalIncorrectCltvExpiry FailCode = 18 - CodeFinalIncorrectHtlcAmount FailCode = 19 - CodeExpiryTooFar FailCode = 21 + CodeNone FailCode = 0 + CodeInvalidRealm = FlagBadOnion | 1 + CodeTemporaryNodeFailure = FlagNode | 2 + CodePermanentNodeFailure = FlagPerm | FlagNode | 2 + CodeRequiredNodeFeatureMissing = FlagPerm | FlagNode | 3 + CodeInvalidOnionVersion = FlagBadOnion | FlagPerm | 4 + CodeInvalidOnionHmac = FlagBadOnion | FlagPerm | 5 + CodeInvalidOnionKey = FlagBadOnion | FlagPerm | 6 + CodeTemporaryChannelFailure = FlagUpdate | 7 + CodePermanentChannelFailure = FlagPerm | 8 + CodeRequiredChannelFeatureMissing = FlagPerm | 9 + CodeUnknownNextPeer = FlagPerm | 10 + CodeAmountBelowMinimum = FlagUpdate | 11 + CodeFeeInsufficient = FlagUpdate | 12 + CodeIncorrectCltvExpiry = FlagUpdate | 13 + CodeExpiryTooSoon = FlagUpdate | 14 + CodeChannelDisabled = FlagUpdate | 20 + CodeIncorrectOrUnknownPaymentDetails = FlagPerm | 15 + CodeIncorrectPaymentAmount = FlagPerm | 16 + CodeFinalExpiryTooSoon FailCode = 17 + CodeFinalIncorrectCltvExpiry FailCode = 18 + CodeFinalIncorrectHtlcAmount FailCode = 19 + CodeExpiryTooFar FailCode = 21 ) // String returns the string representation of the failure code. @@ -134,8 +134,8 @@ func (c FailCode) String() string { case CodeChannelDisabled: return "ChannelDisabled" - case CodeUnknownPaymentHash: - return "UnknownPaymentHash" + case CodeIncorrectOrUnknownPaymentDetails: + return "IncorrectOrUnknownPaymentDetails" case CodeFinalExpiryTooSoon: return "FinalExpiryTooSoon" @@ -317,7 +317,7 @@ func (f *FailIncorrectPaymentAmount) Error() string { return f.Code().String() } -// FailUnknownPaymentHash is returned for two reasons: +// FailIncorrectDetails is returned for two reasons: // // 1) if the payment hash has already been paid, the final node MAY treat the // payment hash as unknown, or may succeed in accepting the HTLC. If the @@ -330,42 +330,56 @@ func (f *FailIncorrectPaymentAmount) Error() string { // gross overpayment. // // NOTE: May only be returned by the final node in the path. -type FailUnknownPaymentHash struct { +type FailIncorrectDetails struct { // amount is the value of the extended HTLC. amount MilliSatoshi + + // height is the block height when the htlc was received. + height uint32 } -// NewFailUnknownPaymentHash makes a new instance of the FailUnknownPaymentHash -// error bound to the specified HTLC amount. -func NewFailUnknownPaymentHash(amt MilliSatoshi) *FailUnknownPaymentHash { - return &FailUnknownPaymentHash{ +// NewFailIncorrectDetails makes a new instance of the FailIncorrectDetails +// error bound to the specified HTLC amount and acceptance height. +func NewFailIncorrectDetails(amt MilliSatoshi, + height uint32) *FailIncorrectDetails { + + return &FailIncorrectDetails{ amount: amt, + height: height, } } // Amount is the value of the extended HTLC. -func (f *FailUnknownPaymentHash) Amount() MilliSatoshi { +func (f *FailIncorrectDetails) Amount() MilliSatoshi { return f.amount } +// Height is the block height when the htlc was received. +func (f *FailIncorrectDetails) Height() uint32 { + return f.height +} + // Code returns the failure unique code. // // NOTE: Part of the FailureMessage interface. -func (f *FailUnknownPaymentHash) Code() FailCode { - return CodeUnknownPaymentHash +func (f *FailIncorrectDetails) Code() FailCode { + return CodeIncorrectOrUnknownPaymentDetails } // Returns a human readable string describing the target FailureMessage. // // NOTE: Implements the error interface. -func (f *FailUnknownPaymentHash) Error() string { - return fmt.Sprintf("UnknownPaymentHash(amt=%v)", f.amount) +func (f *FailIncorrectDetails) Error() string { + return fmt.Sprintf( + "%v(amt=%v, height=%v)", CodeIncorrectOrUnknownPaymentDetails, + f.amount, f.height, + ) } // Decode decodes the failure from bytes stream. // // NOTE: Part of the Serializable interface. -func (f *FailUnknownPaymentHash) Decode(r io.Reader, pver uint32) error { +func (f *FailIncorrectDetails) Decode(r io.Reader, pver uint32) error { err := ReadElement(r, &f.amount) switch { // This is an optional tack on that was added later in the protocol. As @@ -379,14 +393,25 @@ func (f *FailUnknownPaymentHash) Decode(r io.Reader, pver uint32) error { return err } + // At a later stage, the height field was also tacked on. We need to + // check for io.EOF here as well. + err = ReadElement(r, &f.height) + switch { + case err == io.EOF: + return nil + + case err != nil: + return err + } + return nil } // Encode writes the failure in bytes stream. // // NOTE: Part of the Serializable interface. -func (f *FailUnknownPaymentHash) Encode(w io.Writer, pver uint32) error { - return WriteElement(w, f.amount) +func (f *FailIncorrectDetails) Encode(w io.Writer, pver uint32) error { + return WriteElements(w, f.amount, f.height) } // FailFinalExpiryTooSoon is returned if the cltv_expiry is too low, the final @@ -1113,10 +1138,16 @@ func DecodeFailure(r io.Reader, pver uint32) (FailureMessage, error) { dataReader := bytes.NewReader(failureData) + return DecodeFailureMessage(dataReader, pver) +} + +// DecodeFailureMessage decodes just the failure message, ignoring any padding +// that may be present at the end. +func DecodeFailureMessage(r io.Reader, pver uint32) (FailureMessage, error) { // Once we have the failure data, we can obtain the failure code from // the first two bytes of the buffer. var codeBytes [2]byte - if _, err := io.ReadFull(dataReader, codeBytes[:]); err != nil { + if _, err := io.ReadFull(r, codeBytes[:]); err != nil { return nil, fmt.Errorf("unable to read failure code: %v", err) } failCode := FailCode(binary.BigEndian.Uint16(codeBytes[:])) @@ -1132,10 +1163,9 @@ func DecodeFailure(r io.Reader, pver uint32) (FailureMessage, error) { // well. switch f := failure.(type) { case Serializable: - if err := f.Decode(dataReader, pver); err != nil { + if err := f.Decode(r, pver); err != nil { return nil, fmt.Errorf("unable to decode error "+ - "update (type=%T, len_bytes=%v, bytes=%x): %v", - failure, failureLength, failureData[:], err) + "update (type=%T): %v", failure, err) } } @@ -1147,26 +1177,11 @@ func DecodeFailure(r io.Reader, pver uint32) (FailureMessage, error) { func EncodeFailure(w io.Writer, failure FailureMessage, pver uint32) error { var failureMessageBuffer bytes.Buffer - // First, we'll write out the error code itself into the failure - // buffer. - var codeBytes [2]byte - code := uint16(failure.Code()) - binary.BigEndian.PutUint16(codeBytes[:], code) - _, err := failureMessageBuffer.Write(codeBytes[:]) + err := EncodeFailureMessage(&failureMessageBuffer, failure, pver) if err != nil { return err } - // Next, some message have an additional message payload, if this is - // one of those types, then we'll also encode the error payload as - // well. - switch failure := failure.(type) { - case Serializable: - if err := failure.Encode(&failureMessageBuffer, pver); err != nil { - return err - } - } - // The combined size of this message must be below the max allowed // failure message length. failureMessage := failureMessageBuffer.Bytes() @@ -1187,6 +1202,32 @@ func EncodeFailure(w io.Writer, failure FailureMessage, pver uint32) error { ) } +// EncodeFailureMessage encodes just the failure message without adding a length +// and padding the message for the onion protocol. +func EncodeFailureMessage(w io.Writer, failure FailureMessage, pver uint32) error { + // First, we'll write out the error code itself into the failure + // buffer. + var codeBytes [2]byte + code := uint16(failure.Code()) + binary.BigEndian.PutUint16(codeBytes[:], code) + _, err := w.Write(codeBytes[:]) + if err != nil { + return err + } + + // Next, some message have an additional message payload, if this is + // one of those types, then we'll also encode the error payload as + // well. + switch failure := failure.(type) { + case Serializable: + if err := failure.Encode(w, pver); err != nil { + return err + } + } + + return nil +} + // makeEmptyOnionError creates a new empty onion error of the proper concrete // type based on the passed failure code. func makeEmptyOnionError(code FailCode) (FailureMessage, error) { @@ -1212,8 +1253,8 @@ func makeEmptyOnionError(code FailCode) (FailureMessage, error) { case CodeUnknownNextPeer: return &FailUnknownNextPeer{}, nil - case CodeUnknownPaymentHash: - return &FailUnknownPaymentHash{}, nil + case CodeIncorrectOrUnknownPaymentDetails: + return &FailIncorrectDetails{}, nil case CodeIncorrectPaymentAmount: return &FailIncorrectPaymentAmount{}, nil diff --git a/vendor/github.com/lightningnetwork/lnd/lnwire/revoke_and_ack.go b/vendor/github.com/lightningnetwork/lnd/lnwire/revoke_and_ack.go index 623bcc3..f639510 100644 --- a/vendor/github.com/lightningnetwork/lnd/lnwire/revoke_and_ack.go +++ b/vendor/github.com/lightningnetwork/lnd/lnwire/revoke_and_ack.go @@ -81,3 +81,11 @@ func (c *RevokeAndAck) MaxPayloadLength(uint32) uint32 { // 32 + 32 + 33 return 97 } + +// TargetChanID returns the channel id of the link for which this message is +// intended. +// +// NOTE: Part of lnd.LinkUpdater interface. +func (c *RevokeAndAck) TargetChanID() ChannelID { + return c.ChanID +} diff --git a/vendor/github.com/lightningnetwork/lnd/lnwire/update_add_htlc.go b/vendor/github.com/lightningnetwork/lnd/lnwire/update_add_htlc.go index d127db4..b3add95 100644 --- a/vendor/github.com/lightningnetwork/lnd/lnwire/update_add_htlc.go +++ b/vendor/github.com/lightningnetwork/lnd/lnwire/update_add_htlc.go @@ -1,6 +1,8 @@ package lnwire -import "io" +import ( + "io" +) // OnionPacketSize is the size of the serialized Sphinx onion packet included // in each UpdateAddHTLC message. The breakdown of the onion packet is as @@ -107,3 +109,11 @@ func (c *UpdateAddHTLC) MaxPayloadLength(uint32) uint32 { // 1450 return 32 + 8 + 4 + 8 + 32 + 1366 } + +// TargetChanID returns the channel id of the link for which this message is +// intended. +// +// NOTE: Part of lnd.LinkUpdater interface. +func (c *UpdateAddHTLC) TargetChanID() ChannelID { + return c.ChanID +} diff --git a/vendor/github.com/lightningnetwork/lnd/lnwire/update_fail_htlc.go b/vendor/github.com/lightningnetwork/lnd/lnwire/update_fail_htlc.go index ed59af1..17fc3cd 100644 --- a/vendor/github.com/lightningnetwork/lnd/lnwire/update_fail_htlc.go +++ b/vendor/github.com/lightningnetwork/lnd/lnwire/update_fail_htlc.go @@ -1,6 +1,8 @@ package lnwire -import "io" +import ( + "io" +) // OpaqueReason is an opaque encrypted byte slice that encodes the exact // failure reason and additional some supplemental data. The contents of this @@ -83,3 +85,11 @@ func (c *UpdateFailHTLC) MaxPayloadLength(uint32) uint32 { return length } + +// TargetChanID returns the channel id of the link for which this message is +// intended. +// +// NOTE: Part of lnd.LinkUpdater interface. +func (c *UpdateFailHTLC) TargetChanID() ChannelID { + return c.ChanID +} diff --git a/vendor/github.com/lightningnetwork/lnd/lnwire/update_fail_malformed_htlc.go b/vendor/github.com/lightningnetwork/lnd/lnwire/update_fail_malformed_htlc.go index 6415b88..68f0a61 100644 --- a/vendor/github.com/lightningnetwork/lnd/lnwire/update_fail_malformed_htlc.go +++ b/vendor/github.com/lightningnetwork/lnd/lnwire/update_fail_malformed_htlc.go @@ -73,3 +73,11 @@ func (c *UpdateFailMalformedHTLC) MaxPayloadLength(uint32) uint32 { // 32 + 8 + 32 + 2 return 74 } + +// TargetChanID returns the channel id of the link for which this message is +// intended. +// +// NOTE: Part of lnd.LinkUpdater interface. +func (c *UpdateFailMalformedHTLC) TargetChanID() ChannelID { + return c.ChanID +} diff --git a/vendor/github.com/lightningnetwork/lnd/lnwire/update_fee.go b/vendor/github.com/lightningnetwork/lnd/lnwire/update_fee.go index fde0cb8..5657633 100644 --- a/vendor/github.com/lightningnetwork/lnd/lnwire/update_fee.go +++ b/vendor/github.com/lightningnetwork/lnd/lnwire/update_fee.go @@ -68,3 +68,11 @@ func (c *UpdateFee) MaxPayloadLength(uint32) uint32 { // 32 + 4 return 36 } + +// TargetChanID returns the channel id of the link for which this message is +// intended. +// +// NOTE: Part of lnd.LinkUpdater interface. +func (c *UpdateFee) TargetChanID() ChannelID { + return c.ChanID +} diff --git a/vendor/github.com/lightningnetwork/lnd/lnwire/update_fulfill_htlc.go b/vendor/github.com/lightningnetwork/lnd/lnwire/update_fulfill_htlc.go index 050e81f..4934400 100644 --- a/vendor/github.com/lightningnetwork/lnd/lnwire/update_fulfill_htlc.go +++ b/vendor/github.com/lightningnetwork/lnd/lnwire/update_fulfill_htlc.go @@ -1,6 +1,8 @@ package lnwire -import "io" +import ( + "io" +) // UpdateFulfillHTLC is sent by Alice to Bob when she wishes to settle a // particular HTLC referenced by its HTLCKey within a specific active channel @@ -76,3 +78,11 @@ func (c *UpdateFulfillHTLC) MaxPayloadLength(uint32) uint32 { // 32 + 8 + 32 return 72 } + +// TargetChanID returns the channel id of the link for which this message is +// intended. +// +// NOTE: Part of lnd.LinkUpdater interface. +func (c *UpdateFulfillHTLC) TargetChanID() ChannelID { + return c.ChanID +} diff --git a/vendor/github.com/lightningnetwork/lnd/zpay32/invoice.go b/vendor/github.com/lightningnetwork/lnd/zpay32/invoice.go index fb79e3c..4e7210f 100644 --- a/vendor/github.com/lightningnetwork/lnd/zpay32/invoice.go +++ b/vendor/github.com/lightningnetwork/lnd/zpay32/invoice.go @@ -3,6 +3,7 @@ package zpay32 import ( "bytes" "encoding/binary" + "errors" "fmt" "strings" "time" @@ -67,6 +68,24 @@ const ( // fieldTypeC contains an optional requested final CLTV delta. fieldTypeC = 24 + + // fieldType9 contains one or more bytes for signaling features + // supported or required by the receiver. + fieldType9 = 5 + + // maxInvoiceLength is the maximum total length an invoice can have. + // This is chosen to be the maximum number of bytes that can fit into a + // single QR code: https://en.wikipedia.org/wiki/QR_code#Storage + maxInvoiceLength = 7089 +) + +var ( + // InvoiceFeatures holds the set of all known feature bits that are + // exposed as BOLT 11 features. + InvoiceFeatures = map[lnwire.FeatureBit]string{} + + // ErrInvoiceTooLarge is returned when an invoice exceeds maxInvoiceLength. + ErrInvoiceTooLarge = errors.New("invoice is too large") ) // MessageSigner is passed to the Encode method to provide a signature @@ -146,6 +165,10 @@ type Invoice struct { // // NOTE: This is optional. RouteHints [][]HopHint + + // Features represents an optional field used to signal optional or + // required support for features by the receiver. + Features *lnwire.FeatureVector } // Amount is a functional option that allows callers of NewInvoice to set the @@ -249,6 +272,12 @@ func NewInvoice(net *chaincfg.Params, paymentHash [32]byte, func Decode(invoice string, net *chaincfg.Params) (*Invoice, error) { decodedInvoice := Invoice{} + // Before bech32 decoding the invoice, make sure that it is not too large. + // This is done as an anti-DoS measure since bech32 decoding is expensive. + if len(invoice) > maxInvoiceLength { + return nil, ErrInvoiceTooLarge + } + // Decode the invoice using the modified bech32 decoder. hrp, data, err := decodeBech32(invoice) if err != nil { @@ -453,6 +482,12 @@ func (invoice *Invoice) Encode(signer MessageSigner) (string, error) { return "", err } + // Before returning, check that the bech32 encoded string is not greater + // than our largest supported invoice size. + if len(b32) > maxInvoiceLength { + return "", ErrInvoiceTooLarge + } + return b32, nil } @@ -504,21 +539,6 @@ func validateInvoice(invoice *Invoice) error { return fmt.Errorf("neither description nor description hash set") } - // We'll restrict invoices to include up to 20 different private route - // hints. We do this to avoid overly large invoices. - if len(invoice.RouteHints) > 20 { - return fmt.Errorf("too many private routes: %d", - len(invoice.RouteHints)) - } - - // Each route hint can have at most 20 hops. - for i, routeHint := range invoice.RouteHints { - if len(routeHint) > 20 { - return fmt.Errorf("route hint %d has too many extra "+ - "hops: %d", i, len(routeHint)) - } - } - // Check that we support the field lengths. if len(invoice.PaymentHash) != 32 { return fmt.Errorf("unsupported payment hash length: %d", @@ -663,6 +683,14 @@ func parseTaggedFields(invoice *Invoice, fields []byte, net *chaincfg.Params) er } invoice.RouteHints = append(invoice.RouteHints, routeHint) + case fieldType9: + if invoice.Features != nil { + // We skip the field if we have already seen a + // supported one. + continue + } + + invoice.Features, err = parseFeatures(base32Data) default: // Ignore unknown type. } @@ -848,6 +876,7 @@ func parseRouteHint(data []byte) ([]HopHint, error) { return nil, err } + // Check that base256Data is a multiple of hopHintLen. if len(base256Data)%hopHintLen != 0 { return nil, fmt.Errorf("expected length multiple of %d bytes, "+ "got %d", hopHintLen, len(base256Data)) @@ -874,6 +903,25 @@ func parseRouteHint(data []byte) ([]HopHint, error) { return routeHint, nil } +// parseFeatures decodes any feature bits directly from the base32 +// representation. +func parseFeatures(data []byte) (*lnwire.FeatureVector, error) { + rawFeatures := lnwire.NewRawFeatureVector() + err := rawFeatures.DecodeBase32(bytes.NewReader(data), len(data)) + if err != nil { + return nil, err + } + + fv := lnwire.NewFeatureVector(rawFeatures, InvoiceFeatures) + unknownFeatures := fv.UnknownRequiredFeatures() + if len(unknownFeatures) > 0 { + return nil, fmt.Errorf("invoice contains unknown required "+ + "features: %v", unknownFeatures) + } + + return fv, nil +} + // writeTaggedFields writes the non-nil tagged fields of the Invoice to the // base32 buffer. func writeTaggedFields(bufferBase32 *bytes.Buffer, invoice *Invoice) error { @@ -1011,7 +1059,7 @@ func writeTaggedFields(bufferBase32 *bytes.Buffer, invoice *Invoice) error { pubKeyBase32, err := bech32.ConvertBits( invoice.Destination.SerializeCompressed(), 8, 5, true) if err != nil { - return nil + return err } if len(pubKeyBase32) != pubKeyBase32Len { @@ -1024,6 +1072,18 @@ func writeTaggedFields(bufferBase32 *bytes.Buffer, invoice *Invoice) error { return err } } + if invoice.Features != nil && invoice.Features.SerializeSize32() > 0 { + var b bytes.Buffer + err := invoice.Features.RawFeatureVector.EncodeBase32(&b) + if err != nil { + return err + } + + err = writeTaggedField(bufferBase32, fieldType9, b.Bytes()) + if err != nil { + return err + } + } return nil } diff --git a/vendor/github.com/miekg/dns/compress_generate.go b/vendor/github.com/miekg/dns/compress_generate.go deleted file mode 100644 index d2e5db2..0000000 --- a/vendor/github.com/miekg/dns/compress_generate.go +++ /dev/null @@ -1,189 +0,0 @@ -//+build ignore - -// compression_generate.go is meant to run with go generate. It will use -// go/{importer,types} to track down all the RR struct types. Then for each type -// it will look to see if there are (compressible) names, if so it will add that -// type to compressionLenHelperType and comressionLenSearchType which "fake" the -// compression so that Len() is fast. -package main - -import ( - "bytes" - "fmt" - "go/format" - "go/importer" - "go/types" - "log" - "os" -) - -var packageHdr = ` -// *** DO NOT MODIFY *** -// AUTOGENERATED BY go generate from compress_generate.go - -package dns - -` - -// getTypeStruct will take a type and the package scope, and return the -// (innermost) struct if the type is considered a RR type (currently defined as -// those structs beginning with a RR_Header, could be redefined as implementing -// the RR interface). The bool return value indicates if embedded structs were -// resolved. -func getTypeStruct(t types.Type, scope *types.Scope) (*types.Struct, bool) { - st, ok := t.Underlying().(*types.Struct) - if !ok { - return nil, false - } - if st.Field(0).Type() == scope.Lookup("RR_Header").Type() { - return st, false - } - if st.Field(0).Anonymous() { - st, _ := getTypeStruct(st.Field(0).Type(), scope) - return st, true - } - return nil, false -} - -func main() { - // Import and type-check the package - pkg, err := importer.Default().Import("github.com/miekg/dns") - fatalIfErr(err) - scope := pkg.Scope() - - var domainTypes []string // Types that have a domain name in them (either compressible or not). - var cdomainTypes []string // Types that have a compressible domain name in them (subset of domainType) -Names: - for _, name := range scope.Names() { - o := scope.Lookup(name) - if o == nil || !o.Exported() { - continue - } - st, _ := getTypeStruct(o.Type(), scope) - if st == nil { - continue - } - if name == "PrivateRR" { - continue - } - - if scope.Lookup("Type"+o.Name()) == nil && o.Name() != "RFC3597" { - log.Fatalf("Constant Type%s does not exist.", o.Name()) - } - - for i := 1; i < st.NumFields(); i++ { - if _, ok := st.Field(i).Type().(*types.Slice); ok { - if st.Tag(i) == `dns:"domain-name"` { - domainTypes = append(domainTypes, o.Name()) - continue Names - } - if st.Tag(i) == `dns:"cdomain-name"` { - cdomainTypes = append(cdomainTypes, o.Name()) - domainTypes = append(domainTypes, o.Name()) - continue Names - } - continue - } - - switch { - case st.Tag(i) == `dns:"domain-name"`: - domainTypes = append(domainTypes, o.Name()) - continue Names - case st.Tag(i) == `dns:"cdomain-name"`: - cdomainTypes = append(cdomainTypes, o.Name()) - domainTypes = append(domainTypes, o.Name()) - continue Names - } - } - } - - b := &bytes.Buffer{} - b.WriteString(packageHdr) - - // compressionLenHelperType - all types that have domain-name/cdomain-name can be used for compressing names - - fmt.Fprint(b, "func compressionLenHelperType(c map[string]int, r RR) {\n") - fmt.Fprint(b, "switch x := r.(type) {\n") - for _, name := range domainTypes { - o := scope.Lookup(name) - st, _ := getTypeStruct(o.Type(), scope) - - fmt.Fprintf(b, "case *%s:\n", name) - for i := 1; i < st.NumFields(); i++ { - out := func(s string) { fmt.Fprintf(b, "compressionLenHelper(c, x.%s)\n", st.Field(i).Name()) } - - if _, ok := st.Field(i).Type().(*types.Slice); ok { - switch st.Tag(i) { - case `dns:"domain-name"`: - fallthrough - case `dns:"cdomain-name"`: - // For HIP we need to slice over the elements in this slice. - fmt.Fprintf(b, `for i := range x.%s { - compressionLenHelper(c, x.%s[i]) - } -`, st.Field(i).Name(), st.Field(i).Name()) - } - continue - } - - switch { - case st.Tag(i) == `dns:"cdomain-name"`: - fallthrough - case st.Tag(i) == `dns:"domain-name"`: - out(st.Field(i).Name()) - } - } - } - fmt.Fprintln(b, "}\n}\n\n") - - // compressionLenSearchType - search cdomain-tags types for compressible names. - - fmt.Fprint(b, "func compressionLenSearchType(c map[string]int, r RR) (int, bool) {\n") - fmt.Fprint(b, "switch x := r.(type) {\n") - for _, name := range cdomainTypes { - o := scope.Lookup(name) - st, _ := getTypeStruct(o.Type(), scope) - - fmt.Fprintf(b, "case *%s:\n", name) - j := 1 - for i := 1; i < st.NumFields(); i++ { - out := func(s string, j int) { - fmt.Fprintf(b, "k%d, ok%d := compressionLenSearch(c, x.%s)\n", j, j, st.Field(i).Name()) - } - - // There are no slice types with names that can be compressed. - - switch { - case st.Tag(i) == `dns:"cdomain-name"`: - out(st.Field(i).Name(), j) - j++ - } - } - k := "k1" - ok := "ok1" - for i := 2; i < j; i++ { - k += fmt.Sprintf(" + k%d", i) - ok += fmt.Sprintf(" && ok%d", i) - } - fmt.Fprintf(b, "return %s, %s\n", k, ok) - } - fmt.Fprintln(b, "}\nreturn 0, false\n}\n\n") - - // gofmt - res, err := format.Source(b.Bytes()) - if err != nil { - b.WriteTo(os.Stderr) - log.Fatal(err) - } - - f, err := os.Create("zcompress.go") - fatalIfErr(err) - defer f.Close() - f.Write(res) -} - -func fatalIfErr(err error) { - if err != nil { - log.Fatal(err) - } -} diff --git a/vendor/github.com/miekg/dns/msg_generate.go b/vendor/github.com/miekg/dns/msg_generate.go deleted file mode 100644 index 4d9f81d..0000000 --- a/vendor/github.com/miekg/dns/msg_generate.go +++ /dev/null @@ -1,349 +0,0 @@ -//+build ignore - -// msg_generate.go is meant to run with go generate. It will use -// go/{importer,types} to track down all the RR struct types. Then for each type -// it will generate pack/unpack methods based on the struct tags. The generated source is -// written to zmsg.go, and is meant to be checked into git. -package main - -import ( - "bytes" - "fmt" - "go/format" - "go/importer" - "go/types" - "log" - "os" - "strings" -) - -var packageHdr = ` -// *** DO NOT MODIFY *** -// AUTOGENERATED BY go generate from msg_generate.go - -package dns - -` - -// getTypeStruct will take a type and the package scope, and return the -// (innermost) struct if the type is considered a RR type (currently defined as -// those structs beginning with a RR_Header, could be redefined as implementing -// the RR interface). The bool return value indicates if embedded structs were -// resolved. -func getTypeStruct(t types.Type, scope *types.Scope) (*types.Struct, bool) { - st, ok := t.Underlying().(*types.Struct) - if !ok { - return nil, false - } - if st.Field(0).Type() == scope.Lookup("RR_Header").Type() { - return st, false - } - if st.Field(0).Anonymous() { - st, _ := getTypeStruct(st.Field(0).Type(), scope) - return st, true - } - return nil, false -} - -func main() { - // Import and type-check the package - pkg, err := importer.Default().Import("github.com/miekg/dns") - fatalIfErr(err) - scope := pkg.Scope() - - // Collect actual types (*X) - var namedTypes []string - for _, name := range scope.Names() { - o := scope.Lookup(name) - if o == nil || !o.Exported() { - continue - } - if st, _ := getTypeStruct(o.Type(), scope); st == nil { - continue - } - if name == "PrivateRR" { - continue - } - - // Check if corresponding TypeX exists - if scope.Lookup("Type"+o.Name()) == nil && o.Name() != "RFC3597" { - log.Fatalf("Constant Type%s does not exist.", o.Name()) - } - - namedTypes = append(namedTypes, o.Name()) - } - - b := &bytes.Buffer{} - b.WriteString(packageHdr) - - fmt.Fprint(b, "// pack*() functions\n\n") - for _, name := range namedTypes { - o := scope.Lookup(name) - st, _ := getTypeStruct(o.Type(), scope) - - fmt.Fprintf(b, "func (rr *%s) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {\n", name) - fmt.Fprint(b, `off, err := rr.Hdr.pack(msg, off, compression, compress) -if err != nil { - return off, err -} -headerEnd := off -`) - for i := 1; i < st.NumFields(); i++ { - o := func(s string) { - fmt.Fprintf(b, s, st.Field(i).Name()) - fmt.Fprint(b, `if err != nil { -return off, err -} -`) - } - - if _, ok := st.Field(i).Type().(*types.Slice); ok { - switch st.Tag(i) { - case `dns:"-"`: // ignored - case `dns:"txt"`: - o("off, err = packStringTxt(rr.%s, msg, off)\n") - case `dns:"opt"`: - o("off, err = packDataOpt(rr.%s, msg, off)\n") - case `dns:"nsec"`: - o("off, err = packDataNsec(rr.%s, msg, off)\n") - case `dns:"domain-name"`: - o("off, err = packDataDomainNames(rr.%s, msg, off, compression, compress)\n") - default: - log.Fatalln(name, st.Field(i).Name(), st.Tag(i)) - } - continue - } - - switch { - case st.Tag(i) == `dns:"-"`: // ignored - case st.Tag(i) == `dns:"cdomain-name"`: - o("off, err = PackDomainName(rr.%s, msg, off, compression, compress)\n") - case st.Tag(i) == `dns:"domain-name"`: - o("off, err = PackDomainName(rr.%s, msg, off, compression, false)\n") - case st.Tag(i) == `dns:"a"`: - o("off, err = packDataA(rr.%s, msg, off)\n") - case st.Tag(i) == `dns:"aaaa"`: - o("off, err = packDataAAAA(rr.%s, msg, off)\n") - case st.Tag(i) == `dns:"uint48"`: - o("off, err = packUint48(rr.%s, msg, off)\n") - case st.Tag(i) == `dns:"txt"`: - o("off, err = packString(rr.%s, msg, off)\n") - - case strings.HasPrefix(st.Tag(i), `dns:"size-base32`): // size-base32 can be packed just like base32 - fallthrough - case st.Tag(i) == `dns:"base32"`: - o("off, err = packStringBase32(rr.%s, msg, off)\n") - - case strings.HasPrefix(st.Tag(i), `dns:"size-base64`): // size-base64 can be packed just like base64 - fallthrough - case st.Tag(i) == `dns:"base64"`: - o("off, err = packStringBase64(rr.%s, msg, off)\n") - - case strings.HasPrefix(st.Tag(i), `dns:"size-hex:SaltLength`): - // directly write instead of using o() so we get the error check in the correct place - field := st.Field(i).Name() - fmt.Fprintf(b, `// Only pack salt if value is not "-", i.e. empty -if rr.%s != "-" { - off, err = packStringHex(rr.%s, msg, off) - if err != nil { - return off, err - } -} -`, field, field) - continue - case strings.HasPrefix(st.Tag(i), `dns:"size-hex`): // size-hex can be packed just like hex - fallthrough - case st.Tag(i) == `dns:"hex"`: - o("off, err = packStringHex(rr.%s, msg, off)\n") - - case st.Tag(i) == `dns:"octet"`: - o("off, err = packStringOctet(rr.%s, msg, off)\n") - case st.Tag(i) == "": - switch st.Field(i).Type().(*types.Basic).Kind() { - case types.Uint8: - o("off, err = packUint8(rr.%s, msg, off)\n") - case types.Uint16: - o("off, err = packUint16(rr.%s, msg, off)\n") - case types.Uint32: - o("off, err = packUint32(rr.%s, msg, off)\n") - case types.Uint64: - o("off, err = packUint64(rr.%s, msg, off)\n") - case types.String: - o("off, err = packString(rr.%s, msg, off)\n") - default: - log.Fatalln(name, st.Field(i).Name()) - } - default: - log.Fatalln(name, st.Field(i).Name(), st.Tag(i)) - } - } - // We have packed everything, only now we know the rdlength of this RR - fmt.Fprintln(b, "rr.Header().Rdlength = uint16(off-headerEnd)") - fmt.Fprintln(b, "return off, nil }\n") - } - - fmt.Fprint(b, "// unpack*() functions\n\n") - for _, name := range namedTypes { - o := scope.Lookup(name) - st, _ := getTypeStruct(o.Type(), scope) - - fmt.Fprintf(b, "func unpack%s(h RR_Header, msg []byte, off int) (RR, int, error) {\n", name) - fmt.Fprintf(b, "rr := new(%s)\n", name) - fmt.Fprint(b, "rr.Hdr = h\n") - fmt.Fprint(b, `if noRdata(h) { -return rr, off, nil - } -var err error -rdStart := off -_ = rdStart - -`) - for i := 1; i < st.NumFields(); i++ { - o := func(s string) { - fmt.Fprintf(b, s, st.Field(i).Name()) - fmt.Fprint(b, `if err != nil { -return rr, off, err -} -`) - } - - // size-* are special, because they reference a struct member we should use for the length. - if strings.HasPrefix(st.Tag(i), `dns:"size-`) { - structMember := structMember(st.Tag(i)) - structTag := structTag(st.Tag(i)) - switch structTag { - case "hex": - fmt.Fprintf(b, "rr.%s, off, err = unpackStringHex(msg, off, off + int(rr.%s))\n", st.Field(i).Name(), structMember) - case "base32": - fmt.Fprintf(b, "rr.%s, off, err = unpackStringBase32(msg, off, off + int(rr.%s))\n", st.Field(i).Name(), structMember) - case "base64": - fmt.Fprintf(b, "rr.%s, off, err = unpackStringBase64(msg, off, off + int(rr.%s))\n", st.Field(i).Name(), structMember) - default: - log.Fatalln(name, st.Field(i).Name(), st.Tag(i)) - } - fmt.Fprint(b, `if err != nil { -return rr, off, err -} -`) - continue - } - - if _, ok := st.Field(i).Type().(*types.Slice); ok { - switch st.Tag(i) { - case `dns:"-"`: // ignored - case `dns:"txt"`: - o("rr.%s, off, err = unpackStringTxt(msg, off)\n") - case `dns:"opt"`: - o("rr.%s, off, err = unpackDataOpt(msg, off)\n") - case `dns:"nsec"`: - o("rr.%s, off, err = unpackDataNsec(msg, off)\n") - case `dns:"domain-name"`: - o("rr.%s, off, err = unpackDataDomainNames(msg, off, rdStart + int(rr.Hdr.Rdlength))\n") - default: - log.Fatalln(name, st.Field(i).Name(), st.Tag(i)) - } - continue - } - - switch st.Tag(i) { - case `dns:"-"`: // ignored - case `dns:"cdomain-name"`: - fallthrough - case `dns:"domain-name"`: - o("rr.%s, off, err = UnpackDomainName(msg, off)\n") - case `dns:"a"`: - o("rr.%s, off, err = unpackDataA(msg, off)\n") - case `dns:"aaaa"`: - o("rr.%s, off, err = unpackDataAAAA(msg, off)\n") - case `dns:"uint48"`: - o("rr.%s, off, err = unpackUint48(msg, off)\n") - case `dns:"txt"`: - o("rr.%s, off, err = unpackString(msg, off)\n") - case `dns:"base32"`: - o("rr.%s, off, err = unpackStringBase32(msg, off, rdStart + int(rr.Hdr.Rdlength))\n") - case `dns:"base64"`: - o("rr.%s, off, err = unpackStringBase64(msg, off, rdStart + int(rr.Hdr.Rdlength))\n") - case `dns:"hex"`: - o("rr.%s, off, err = unpackStringHex(msg, off, rdStart + int(rr.Hdr.Rdlength))\n") - case `dns:"octet"`: - o("rr.%s, off, err = unpackStringOctet(msg, off)\n") - case "": - switch st.Field(i).Type().(*types.Basic).Kind() { - case types.Uint8: - o("rr.%s, off, err = unpackUint8(msg, off)\n") - case types.Uint16: - o("rr.%s, off, err = unpackUint16(msg, off)\n") - case types.Uint32: - o("rr.%s, off, err = unpackUint32(msg, off)\n") - case types.Uint64: - o("rr.%s, off, err = unpackUint64(msg, off)\n") - case types.String: - o("rr.%s, off, err = unpackString(msg, off)\n") - default: - log.Fatalln(name, st.Field(i).Name()) - } - default: - log.Fatalln(name, st.Field(i).Name(), st.Tag(i)) - } - // If we've hit len(msg) we return without error. - if i < st.NumFields()-1 { - fmt.Fprintf(b, `if off == len(msg) { -return rr, off, nil - } -`) - } - } - fmt.Fprintf(b, "return rr, off, err }\n\n") - } - // Generate typeToUnpack map - fmt.Fprintln(b, "var typeToUnpack = map[uint16]func(RR_Header, []byte, int) (RR, int, error){") - for _, name := range namedTypes { - if name == "RFC3597" { - continue - } - fmt.Fprintf(b, "Type%s: unpack%s,\n", name, name) - } - fmt.Fprintln(b, "}\n") - - // gofmt - res, err := format.Source(b.Bytes()) - if err != nil { - b.WriteTo(os.Stderr) - log.Fatal(err) - } - - // write result - f, err := os.Create("zmsg.go") - fatalIfErr(err) - defer f.Close() - f.Write(res) -} - -// structMember will take a tag like dns:"size-base32:SaltLength" and return the last part of this string. -func structMember(s string) string { - fields := strings.Split(s, ":") - if len(fields) == 0 { - return "" - } - f := fields[len(fields)-1] - // f should have a closing " - if len(f) > 1 { - return f[:len(f)-1] - } - return f -} - -// structTag will take a tag like dns:"size-base32:SaltLength" and return base32. -func structTag(s string) string { - fields := strings.Split(s, ":") - if len(fields) < 2 { - return "" - } - return fields[1][len("\"size-"):] -} - -func fatalIfErr(err error) { - if err != nil { - log.Fatal(err) - } -} diff --git a/vendor/github.com/miekg/dns/types_generate.go b/vendor/github.com/miekg/dns/types_generate.go deleted file mode 100644 index 73720fe..0000000 --- a/vendor/github.com/miekg/dns/types_generate.go +++ /dev/null @@ -1,271 +0,0 @@ -//+build ignore - -// types_generate.go is meant to run with go generate. It will use -// go/{importer,types} to track down all the RR struct types. Then for each type -// it will generate conversion tables (TypeToRR and TypeToString) and banal -// methods (len, Header, copy) based on the struct tags. The generated source is -// written to ztypes.go, and is meant to be checked into git. -package main - -import ( - "bytes" - "fmt" - "go/format" - "go/importer" - "go/types" - "log" - "os" - "strings" - "text/template" -) - -var skipLen = map[string]struct{}{ - "NSEC": {}, - "NSEC3": {}, - "OPT": {}, - "CSYNC": {}, -} - -var packageHdr = ` -// *** DO NOT MODIFY *** -// AUTOGENERATED BY go generate from types_generate.go - -package dns - -import ( - "encoding/base64" - "net" -) - -` - -var TypeToRR = template.Must(template.New("TypeToRR").Parse(` -// TypeToRR is a map of constructors for each RR type. -var TypeToRR = map[uint16]func() RR{ -{{range .}}{{if ne . "RFC3597"}} Type{{.}}: func() RR { return new({{.}}) }, -{{end}}{{end}} } - -`)) - -var typeToString = template.Must(template.New("typeToString").Parse(` -// TypeToString is a map of strings for each RR type. -var TypeToString = map[uint16]string{ -{{range .}}{{if ne . "NSAPPTR"}} Type{{.}}: "{{.}}", -{{end}}{{end}} TypeNSAPPTR: "NSAP-PTR", -} - -`)) - -var headerFunc = template.Must(template.New("headerFunc").Parse(` -{{range .}} func (rr *{{.}}) Header() *RR_Header { return &rr.Hdr } -{{end}} - -`)) - -// getTypeStruct will take a type and the package scope, and return the -// (innermost) struct if the type is considered a RR type (currently defined as -// those structs beginning with a RR_Header, could be redefined as implementing -// the RR interface). The bool return value indicates if embedded structs were -// resolved. -func getTypeStruct(t types.Type, scope *types.Scope) (*types.Struct, bool) { - st, ok := t.Underlying().(*types.Struct) - if !ok { - return nil, false - } - if st.Field(0).Type() == scope.Lookup("RR_Header").Type() { - return st, false - } - if st.Field(0).Anonymous() { - st, _ := getTypeStruct(st.Field(0).Type(), scope) - return st, true - } - return nil, false -} - -func main() { - // Import and type-check the package - pkg, err := importer.Default().Import("github.com/miekg/dns") - fatalIfErr(err) - scope := pkg.Scope() - - // Collect constants like TypeX - var numberedTypes []string - for _, name := range scope.Names() { - o := scope.Lookup(name) - if o == nil || !o.Exported() { - continue - } - b, ok := o.Type().(*types.Basic) - if !ok || b.Kind() != types.Uint16 { - continue - } - if !strings.HasPrefix(o.Name(), "Type") { - continue - } - name := strings.TrimPrefix(o.Name(), "Type") - if name == "PrivateRR" { - continue - } - numberedTypes = append(numberedTypes, name) - } - - // Collect actual types (*X) - var namedTypes []string - for _, name := range scope.Names() { - o := scope.Lookup(name) - if o == nil || !o.Exported() { - continue - } - if st, _ := getTypeStruct(o.Type(), scope); st == nil { - continue - } - if name == "PrivateRR" { - continue - } - - // Check if corresponding TypeX exists - if scope.Lookup("Type"+o.Name()) == nil && o.Name() != "RFC3597" { - log.Fatalf("Constant Type%s does not exist.", o.Name()) - } - - namedTypes = append(namedTypes, o.Name()) - } - - b := &bytes.Buffer{} - b.WriteString(packageHdr) - - // Generate TypeToRR - fatalIfErr(TypeToRR.Execute(b, namedTypes)) - - // Generate typeToString - fatalIfErr(typeToString.Execute(b, numberedTypes)) - - // Generate headerFunc - fatalIfErr(headerFunc.Execute(b, namedTypes)) - - // Generate len() - fmt.Fprint(b, "// len() functions\n") - for _, name := range namedTypes { - if _, ok := skipLen[name]; ok { - continue - } - o := scope.Lookup(name) - st, isEmbedded := getTypeStruct(o.Type(), scope) - if isEmbedded { - continue - } - fmt.Fprintf(b, "func (rr *%s) len() int {\n", name) - fmt.Fprintf(b, "l := rr.Hdr.len()\n") - for i := 1; i < st.NumFields(); i++ { - o := func(s string) { fmt.Fprintf(b, s, st.Field(i).Name()) } - - if _, ok := st.Field(i).Type().(*types.Slice); ok { - switch st.Tag(i) { - case `dns:"-"`: - // ignored - case `dns:"cdomain-name"`, `dns:"domain-name"`, `dns:"txt"`: - o("for _, x := range rr.%s { l += len(x) + 1 }\n") - default: - log.Fatalln(name, st.Field(i).Name(), st.Tag(i)) - } - continue - } - - switch { - case st.Tag(i) == `dns:"-"`: - // ignored - case st.Tag(i) == `dns:"cdomain-name"`, st.Tag(i) == `dns:"domain-name"`: - o("l += len(rr.%s) + 1\n") - case st.Tag(i) == `dns:"octet"`: - o("l += len(rr.%s)\n") - case strings.HasPrefix(st.Tag(i), `dns:"size-base64`): - fallthrough - case st.Tag(i) == `dns:"base64"`: - o("l += base64.StdEncoding.DecodedLen(len(rr.%s))\n") - case strings.HasPrefix(st.Tag(i), `dns:"size-hex`): - fallthrough - case st.Tag(i) == `dns:"hex"`: - o("l += len(rr.%s)/2 + 1\n") - case st.Tag(i) == `dns:"a"`: - o("l += net.IPv4len // %s\n") - case st.Tag(i) == `dns:"aaaa"`: - o("l += net.IPv6len // %s\n") - case st.Tag(i) == `dns:"txt"`: - o("for _, t := range rr.%s { l += len(t) + 1 }\n") - case st.Tag(i) == `dns:"uint48"`: - o("l += 6 // %s\n") - case st.Tag(i) == "": - switch st.Field(i).Type().(*types.Basic).Kind() { - case types.Uint8: - o("l++ // %s\n") - case types.Uint16: - o("l += 2 // %s\n") - case types.Uint32: - o("l += 4 // %s\n") - case types.Uint64: - o("l += 8 // %s\n") - case types.String: - o("l += len(rr.%s) + 1\n") - default: - log.Fatalln(name, st.Field(i).Name()) - } - default: - log.Fatalln(name, st.Field(i).Name(), st.Tag(i)) - } - } - fmt.Fprintf(b, "return l }\n") - } - - // Generate copy() - fmt.Fprint(b, "// copy() functions\n") - for _, name := range namedTypes { - o := scope.Lookup(name) - st, isEmbedded := getTypeStruct(o.Type(), scope) - if isEmbedded { - continue - } - fmt.Fprintf(b, "func (rr *%s) copy() RR {\n", name) - fields := []string{"*rr.Hdr.copyHeader()"} - for i := 1; i < st.NumFields(); i++ { - f := st.Field(i).Name() - if sl, ok := st.Field(i).Type().(*types.Slice); ok { - t := sl.Underlying().String() - t = strings.TrimPrefix(t, "[]") - if strings.Contains(t, ".") { - splits := strings.Split(t, ".") - t = splits[len(splits)-1] - } - fmt.Fprintf(b, "%s := make([]%s, len(rr.%s)); copy(%s, rr.%s)\n", - f, t, f, f, f) - fields = append(fields, f) - continue - } - if st.Field(i).Type().String() == "net.IP" { - fields = append(fields, "copyIP(rr."+f+")") - continue - } - fields = append(fields, "rr."+f) - } - fmt.Fprintf(b, "return &%s{%s}\n", name, strings.Join(fields, ",")) - fmt.Fprintf(b, "}\n") - } - - // gofmt - res, err := format.Source(b.Bytes()) - if err != nil { - b.WriteTo(os.Stderr) - log.Fatal(err) - } - - // write result - f, err := os.Create("ztypes.go") - fatalIfErr(err) - defer f.Close() - f.Write(res) -} - -func fatalIfErr(err error) { - if err != nil { - log.Fatal(err) - } -} diff --git a/vendor/google.golang.org/grpc/AUTHORS b/vendor/google.golang.org/grpc/AUTHORS deleted file mode 100644 index e491a9e..0000000 --- a/vendor/google.golang.org/grpc/AUTHORS +++ /dev/null @@ -1 +0,0 @@ -Google Inc. diff --git a/vendor/google.golang.org/grpc/LICENSE b/vendor/google.golang.org/grpc/LICENSE deleted file mode 100644 index d645695..0000000 --- a/vendor/google.golang.org/grpc/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/google.golang.org/grpc/codes/code_string.go b/vendor/google.golang.org/grpc/codes/code_string.go deleted file mode 100644 index 0b206a5..0000000 --- a/vendor/google.golang.org/grpc/codes/code_string.go +++ /dev/null @@ -1,62 +0,0 @@ -/* - * - * Copyright 2017 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package codes - -import "strconv" - -func (c Code) String() string { - switch c { - case OK: - return "OK" - case Canceled: - return "Canceled" - case Unknown: - return "Unknown" - case InvalidArgument: - return "InvalidArgument" - case DeadlineExceeded: - return "DeadlineExceeded" - case NotFound: - return "NotFound" - case AlreadyExists: - return "AlreadyExists" - case PermissionDenied: - return "PermissionDenied" - case ResourceExhausted: - return "ResourceExhausted" - case FailedPrecondition: - return "FailedPrecondition" - case Aborted: - return "Aborted" - case OutOfRange: - return "OutOfRange" - case Unimplemented: - return "Unimplemented" - case Internal: - return "Internal" - case Unavailable: - return "Unavailable" - case DataLoss: - return "DataLoss" - case Unauthenticated: - return "Unauthenticated" - default: - return "Code(" + strconv.FormatInt(int64(c), 10) + ")" - } -} diff --git a/vendor/google.golang.org/grpc/codes/codes.go b/vendor/google.golang.org/grpc/codes/codes.go deleted file mode 100644 index d9b9d57..0000000 --- a/vendor/google.golang.org/grpc/codes/codes.go +++ /dev/null @@ -1,197 +0,0 @@ -/* - * - * Copyright 2014 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -// Package codes defines the canonical error codes used by gRPC. It is -// consistent across various languages. -package codes // import "google.golang.org/grpc/codes" - -import ( - "fmt" - "strconv" -) - -// A Code is an unsigned 32-bit error code as defined in the gRPC spec. -type Code uint32 - -const ( - // OK is returned on success. - OK Code = 0 - - // Canceled indicates the operation was canceled (typically by the caller). - Canceled Code = 1 - - // Unknown error. An example of where this error may be returned is - // if a Status value received from another address space belongs to - // an error-space that is not known in this address space. Also - // errors raised by APIs that do not return enough error information - // may be converted to this error. - Unknown Code = 2 - - // InvalidArgument indicates client specified an invalid argument. - // Note that this differs from FailedPrecondition. It indicates arguments - // that are problematic regardless of the state of the system - // (e.g., a malformed file name). - InvalidArgument Code = 3 - - // DeadlineExceeded means operation expired before completion. - // For operations that change the state of the system, this error may be - // returned even if the operation has completed successfully. For - // example, a successful response from a server could have been delayed - // long enough for the deadline to expire. - DeadlineExceeded Code = 4 - - // NotFound means some requested entity (e.g., file or directory) was - // not found. - NotFound Code = 5 - - // AlreadyExists means an attempt to create an entity failed because one - // already exists. - AlreadyExists Code = 6 - - // PermissionDenied indicates the caller does not have permission to - // execute the specified operation. It must not be used for rejections - // caused by exhausting some resource (use ResourceExhausted - // instead for those errors). It must not be - // used if the caller cannot be identified (use Unauthenticated - // instead for those errors). - PermissionDenied Code = 7 - - // ResourceExhausted indicates some resource has been exhausted, perhaps - // a per-user quota, or perhaps the entire file system is out of space. - ResourceExhausted Code = 8 - - // FailedPrecondition indicates operation was rejected because the - // system is not in a state required for the operation's execution. - // For example, directory to be deleted may be non-empty, an rmdir - // operation is applied to a non-directory, etc. - // - // A litmus test that may help a service implementor in deciding - // between FailedPrecondition, Aborted, and Unavailable: - // (a) Use Unavailable if the client can retry just the failing call. - // (b) Use Aborted if the client should retry at a higher-level - // (e.g., restarting a read-modify-write sequence). - // (c) Use FailedPrecondition if the client should not retry until - // the system state has been explicitly fixed. E.g., if an "rmdir" - // fails because the directory is non-empty, FailedPrecondition - // should be returned since the client should not retry unless - // they have first fixed up the directory by deleting files from it. - // (d) Use FailedPrecondition if the client performs conditional - // REST Get/Update/Delete on a resource and the resource on the - // server does not match the condition. E.g., conflicting - // read-modify-write on the same resource. - FailedPrecondition Code = 9 - - // Aborted indicates the operation was aborted, typically due to a - // concurrency issue like sequencer check failures, transaction aborts, - // etc. - // - // See litmus test above for deciding between FailedPrecondition, - // Aborted, and Unavailable. - Aborted Code = 10 - - // OutOfRange means operation was attempted past the valid range. - // E.g., seeking or reading past end of file. - // - // Unlike InvalidArgument, this error indicates a problem that may - // be fixed if the system state changes. For example, a 32-bit file - // system will generate InvalidArgument if asked to read at an - // offset that is not in the range [0,2^32-1], but it will generate - // OutOfRange if asked to read from an offset past the current - // file size. - // - // There is a fair bit of overlap between FailedPrecondition and - // OutOfRange. We recommend using OutOfRange (the more specific - // error) when it applies so that callers who are iterating through - // a space can easily look for an OutOfRange error to detect when - // they are done. - OutOfRange Code = 11 - - // Unimplemented indicates operation is not implemented or not - // supported/enabled in this service. - Unimplemented Code = 12 - - // Internal errors. Means some invariants expected by underlying - // system has been broken. If you see one of these errors, - // something is very broken. - Internal Code = 13 - - // Unavailable indicates the service is currently unavailable. - // This is a most likely a transient condition and may be corrected - // by retrying with a backoff. - // - // See litmus test above for deciding between FailedPrecondition, - // Aborted, and Unavailable. - Unavailable Code = 14 - - // DataLoss indicates unrecoverable data loss or corruption. - DataLoss Code = 15 - - // Unauthenticated indicates the request does not have valid - // authentication credentials for the operation. - Unauthenticated Code = 16 - - _maxCode = 17 -) - -var strToCode = map[string]Code{ - `"OK"`: OK, - `"CANCELLED"`:/* [sic] */ Canceled, - `"UNKNOWN"`: Unknown, - `"INVALID_ARGUMENT"`: InvalidArgument, - `"DEADLINE_EXCEEDED"`: DeadlineExceeded, - `"NOT_FOUND"`: NotFound, - `"ALREADY_EXISTS"`: AlreadyExists, - `"PERMISSION_DENIED"`: PermissionDenied, - `"RESOURCE_EXHAUSTED"`: ResourceExhausted, - `"FAILED_PRECONDITION"`: FailedPrecondition, - `"ABORTED"`: Aborted, - `"OUT_OF_RANGE"`: OutOfRange, - `"UNIMPLEMENTED"`: Unimplemented, - `"INTERNAL"`: Internal, - `"UNAVAILABLE"`: Unavailable, - `"DATA_LOSS"`: DataLoss, - `"UNAUTHENTICATED"`: Unauthenticated, -} - -// UnmarshalJSON unmarshals b into the Code. -func (c *Code) UnmarshalJSON(b []byte) error { - // From json.Unmarshaler: By convention, to approximate the behavior of - // Unmarshal itself, Unmarshalers implement UnmarshalJSON([]byte("null")) as - // a no-op. - if string(b) == "null" { - return nil - } - if c == nil { - return fmt.Errorf("nil receiver passed to UnmarshalJSON") - } - - if ci, err := strconv.ParseUint(string(b), 10, 32); err == nil { - if ci >= _maxCode { - return fmt.Errorf("invalid code: %q", ci) - } - - *c = Code(ci) - return nil - } - - if jc, ok := strToCode[string(b)]; ok { - *c = jc - return nil - } - return fmt.Errorf("invalid code: %q", string(b)) -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 9ef72d6..b724162 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,38 +1,36 @@ -# github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3 +# github.com/btcsuite/btcd v0.20.1-beta github.com/btcsuite/btcd/btcec github.com/btcsuite/btcd/chaincfg -github.com/btcsuite/btcd/txscript -github.com/btcsuite/btcd/wire github.com/btcsuite/btcd/chaincfg/chainhash github.com/btcsuite/btcd/connmgr +github.com/btcsuite/btcd/txscript +github.com/btcsuite/btcd/wire # github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f github.com/btcsuite/btclog # github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d github.com/btcsuite/btcutil github.com/btcsuite/btcutil/base58 -github.com/btcsuite/btcutil/hdkeychain github.com/btcsuite/btcutil/bech32 +github.com/btcsuite/btcutil/hdkeychain # github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew/spew # github.com/go-errors/errors v1.0.1 github.com/go-errors/errors # github.com/golang/protobuf v1.3.2 github.com/golang/protobuf/proto -# github.com/lightningnetwork/lnd v0.7.1-beta-rc2 -github.com/lightningnetwork/lnd/zpay32 +# github.com/lightningnetwork/lnd v0.8.0-beta github.com/lightningnetwork/lnd/lnwire github.com/lightningnetwork/lnd/tor +github.com/lightningnetwork/lnd/zpay32 # github.com/miekg/dns v0.0.0-20171125082028-79bfde677fa8 github.com/miekg/dns github.com/miekg/dns/internal/socket # github.com/pkg/errors v0.8.1 github.com/pkg/errors # golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7 +golang.org/x/crypto/pbkdf2 golang.org/x/crypto/ripemd160 golang.org/x/crypto/scrypt -golang.org/x/crypto/pbkdf2 # golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 -golang.org/x/net/proxy golang.org/x/net/internal/socks -# google.golang.org/grpc v1.18.0 -google.golang.org/grpc/codes +golang.org/x/net/proxy