Skip to content

Commit

Permalink
Merge pull request #17 from libp2p/feat/transport-options
Browse files Browse the repository at this point in the history
use Options to configure transport
  • Loading branch information
yusefnapora committed Dec 11, 2019
2 parents 30b7a7d + 8ab00e7 commit fc5d113
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 13 deletions.
24 changes: 17 additions & 7 deletions p2p/security/noise/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"context"
"crypto/rand"
"fmt"
libp2p "github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/host"
net "github.com/libp2p/go-libp2p-core/network"
Expand Down Expand Up @@ -39,13 +39,10 @@ func makeNode(t *testing.T, seed int64, port int, kp *Keypair) (host.Host, error
t.Fatal(err)
}

pid, err := peer.IDFromPrivateKey(priv)
tpt, err := New(priv, NoiseKeyPair(kp))
if err != nil {
t.Fatal(err)
}

tpt := NewTransport(pid, priv, false, kp)

ip := "0.0.0.0"
addr, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ip, port))
if err != nil {
Expand All @@ -69,12 +66,11 @@ func makeNodePipes(t *testing.T, seed int64, port int, rpid peer.ID, rpubkey [32
t.Fatal(err)
}

pid, err := peer.IDFromPrivateKey(priv)
tpt, err := New(priv, UseNoisePipes, NoiseKeyPair(kp))
if err != nil {
t.Fatal(err)
}

tpt := NewTransport(pid, priv, true, kp)
tpt.NoiseStaticKeyCache = NewKeyCache()
tpt.NoiseStaticKeyCache.Store(rpid, rpubkey)

Expand Down Expand Up @@ -256,6 +252,20 @@ func TestLibp2pIntegration_XXFallback(t *testing.T) {
time.Sleep(time.Second)
}

func TestConstrucingWithMaker(t *testing.T) {
kp := GenerateKeypair()

ctx := context.Background()
h, err := libp2p.New(ctx,
libp2p.Security(ID,
Maker(NoiseKeyPair(kp), UseNoisePipes)))

if err != nil {
t.Fatalf("unable to create libp2p host with Maker: %v", err)
}
_ = h.Close()
}

func handleStream(stream net.Stream) {
defer func() {
if err := stream.Close(); err != nil {
Expand Down
44 changes: 44 additions & 0 deletions p2p/security/noise/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package noise

// UseNoisePipes configures the Noise transport to use the Noise Pipes pattern.
// Noise Pipes attempts to use the more efficient IK handshake pattern when
// dialing a remote peer, if that peer's static Noise key is known. If this
// is unsuccessful, the transport will fallback to using the default XX pattern.
//
// Note that the fallback does not add any additional round-trips vs. simply
// using XX in the first place, however there is a slight processing overhead
// due to the initial decryption attempt of the IK message.
func UseNoisePipes(cfg *config) {
cfg.NoisePipesSupport = true
}

// NoiseKeyPair configures the Noise transport to use the given Noise static
// keypair. This is distinct from the libp2p Host's identity keypair and is
// used only for Noise. If this option is not provided, a new Noise static
// keypair will be generated when the transport is initialized.
//
// This option is most useful when Noise Pipes is enabled, as longer static
// key lifetimes may lead to more successful IK handshake attempts.
//
// If you do use this option with a key that's been saved to disk, you must
// take care to store the key securely!
func NoiseKeyPair(kp *Keypair) Option {
return func(cfg *config) {
cfg.NoiseKeypair = kp
}
}

type config struct {
NoiseKeypair *Keypair
NoisePipesSupport bool
}

type Option func(cfg *config)

func (cfg *config) applyOptions(opts ...Option) {
for _, opt := range opts {
if opt != nil {
opt(cfg)
}
}
}
68 changes: 62 additions & 6 deletions p2p/security/noise/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,26 +42,82 @@ type Transport struct {
NoiseKeypair *Keypair
}

// NewTransport creates a new noise transport and can be configured to use noise pipes and a given
// noise ed25519 keypair
func NewTransport(localID peer.ID, privkey crypto.PrivKey, noisePipesSupport bool, kp *Keypair) *Transport {
type transportConstructor func(crypto.PrivKey) (*Transport, error)

// Maker returns a function that will construct a new Noise transport
// using the given Options. The returned function may be provided as a libp2p.Security
// option when configuring a libp2p Host using libp2p.New, and is compatible with the
// "reflection magic" that libp2p.New uses to inject the private identity key:
//
// host := libp2p.New(
// libp2p.Security(noise.ID, noise.Maker()))
//
// The transport can be configured by passing in Options.
//
// To enable the Noise Pipes pattern (which can be more efficient when reconnecting
// to a known peer), pass in the UseNoisePipes Option:
//
// Maker(UseNoisePipes)
//
// To use a specific Noise keypair, pass in the NoiseKeyPair(kp) option, where
// kp is a noise.Keypair struct. This is most useful when using Noise Pipes, whose
// efficiency gains rely on the static Noise key being known in advance. Persisting
// the Noise keypair across process restarts makes it more likely that other peers
// will be able to use the more efficient IK handshake pattern.
//
// Maker(UseNoisePipes, NoiseKeypair(keypairLoadedFromDisk))
func Maker(options ...Option) transportConstructor {
return func(privKey crypto.PrivKey) (*Transport, error) {
return New(privKey, options...)
}
}

// New creates a new Noise transport using the given private key as its
// libp2p identity key. This function may be used when you want a transport
// instance and know the libp2p Host's identity key before the Host is initialized.
// When configuring a go-libp2p Host using libp2p.New, it's simpler to use
// Maker instead, which will receive the identity key when the Host
// is initialized.
//
// New supports all the same Options as noise.Maker.
//
// To configure a go-libp2p Host to use the newly created transport, pass it into
// libp2p.New wrapped in a libp2p.Security Option. You will also need to
// make sure to set the libp2p.Identity option so that the Host uses the same
// identity key:
//
// privkey := loadPrivateKeyFromSomewhere()
// noiseTpt := noise.New(privkey)
// host := libp2p.New(
// libp2p.Identity(privkey),
// libp2p.Security(noise.ID, noiseTpt))
func New(privkey crypto.PrivKey, options ...Option) (*Transport, error) {
localID, err := peer.IDFromPrivateKey(privkey)
if err != nil {
return nil, err
}

cfg := config{}
cfg.applyOptions(options...)

kp := cfg.NoiseKeypair
if kp == nil {
kp = GenerateKeypair()
}

// the static key cache is only useful if Noise Pipes is enabled
var keyCache *KeyCache
if noisePipesSupport {
if cfg.NoisePipesSupport {
keyCache = NewKeyCache()
}

return &Transport{
LocalID: localID,
PrivateKey: privkey,
NoisePipesSupport: noisePipesSupport,
NoisePipesSupport: cfg.NoisePipesSupport,
NoiseKeypair: kp,
NoiseStaticKeyCache: keyCache,
}
}, nil
}

// SecureInbound runs noise handshake as the responder
Expand Down

0 comments on commit fc5d113

Please sign in to comment.