From 3698d25fed31415017de44f4739372cf002cf7ce Mon Sep 17 00:00:00 2001 From: Brendan Mc Date: Wed, 30 Jul 2014 21:20:33 -0400 Subject: [PATCH 1/5] Paths can be expressed as base58 hashes, proquint ids, or as domain names. --- name/name.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ path/path.go | 17 ++++++++--------- 2 files changed, 53 insertions(+), 9 deletions(-) create mode 100644 name/name.go diff --git a/name/name.go b/name/name.go new file mode 100644 index 00000000000..c549e9552b3 --- /dev/null +++ b/name/name.go @@ -0,0 +1,45 @@ +package naming + +import ( + "net" + "strings" + "regexp" + "errors" + proquint "github.com/Bren2010/proquint" + mh "github.com/jbenet/go-multihash" +) + +func Resolve(name string) (mh.Multihash, error) { + b58Exp := "^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]*$" + pqExp := "^([abdfghijklmnoprstuvz]{5}-)*[abdfghijklmnoprstuvz]{5}$" + + isB58, err := regexp.MatchString(b58Exp, name) + isPQ, err := regexp.MatchString(pqExp, name) + + if err != nil { + return nil, err + } + + if isB58 { // Is a base58 hash. + h, err := mh.FromB58String(name) + return h, err + } else if isPQ { // Is a Proquint identifier. + return mh.Multihash(proquint.Decode(name)), nil + } else { // Is a domain name. Hopefully. + txts, err := net.LookupTXT(name) + if err != nil { + return nil, err + } + + for i := 0; i < len(txts); i++ { + var parts []string = strings.SplitN(txts[i], "=", 2) + + if len(parts) == 2 && parts[0] == "ipfs" { + h, err := mh.FromB58String(parts[1]) + return h, err + } + } + + return nil, errors.New("Could not resolve IPNS.") + } +} diff --git a/path/path.go b/path/path.go index 3f1c3997e4c..fe12a9d5f2d 100644 --- a/path/path.go +++ b/path/path.go @@ -4,7 +4,7 @@ import ( "fmt" merkledag "github.com/jbenet/go-ipfs/merkledag" u "github.com/jbenet/go-ipfs/util" - mh "github.com/jbenet/go-multihash" + name "github.com/jbenet/go-ipfs/name" "path" "strings" ) @@ -33,16 +33,15 @@ func (s *Resolver) ResolvePath(fpath string) (*merkledag.Node, error) { return nil, fmt.Errorf("ipfs path must contain at least one component") } - // first element in the path is a b58 hash (for now) - h, err := mh.FromB58String(parts[0]) - if err != nil { - return nil, err + h, err := name.Resolve(parts[0]) + if err != nil { + return nil, err } - nd, err := s.DAG.Get(u.Key(h)) - if err != nil { - return nil, err - } + nd, err := s.DAG.Get(u.Key(h)) + if err != nil { + return nil, err + } return s.ResolveLinks(nd, parts[1:]) } From 0477d2302034be5976172aecd6cfd731d95f2cb3 Mon Sep 17 00:00:00 2001 From: Brendan Mc Date: Wed, 30 Jul 2014 23:15:36 -0400 Subject: [PATCH 2/5] Typo: Dropped an error. --- name/name.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/name/name.go b/name/name.go index c549e9552b3..33c091b5962 100644 --- a/name/name.go +++ b/name/name.go @@ -14,8 +14,11 @@ func Resolve(name string) (mh.Multihash, error) { pqExp := "^([abdfghijklmnoprstuvz]{5}-)*[abdfghijklmnoprstuvz]{5}$" isB58, err := regexp.MatchString(b58Exp, name) + if err != nil { + return nil, err + } + isPQ, err := regexp.MatchString(pqExp, name) - if err != nil { return nil, err } From 321a6e685dd76df674a962220fd9ce6c83205b9c Mon Sep 17 00:00:00 2001 From: Brendan Mc Date: Thu, 31 Jul 2014 14:10:02 -0400 Subject: [PATCH 3/5] Signing, Verifying, and generating a shared secret for peers. --- config/config.go | 6 +- core/core.go | 6 ++ name/name.go | 6 +- peer/peer.go | 149 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 161 insertions(+), 6 deletions(-) diff --git a/config/config.go b/config/config.go index f1907edf1f7..779146057c0 100644 --- a/config/config.go +++ b/config/config.go @@ -7,7 +7,7 @@ import ( // Identity tracks the configuration of the local node's identity. type Identity struct { - PeerID string + Curve uint16 } // Datastore tracks the configuration of the datastore. @@ -24,7 +24,9 @@ type Config struct { var defaultConfigFilePath = "~/.go-ipfs/config" var defaultConfigFile = `{ - "identity": {}, + "identity": { + "curve": 224 + }, "datastore": { "type": "leveldb", "path": "~/.go-ipfs/datastore" diff --git a/core/core.go b/core/core.go index 66058cf61c2..db6f7d626f3 100644 --- a/core/core.go +++ b/core/core.go @@ -53,6 +53,11 @@ func NewIpfsNode(cfg *config.Config) (*IpfsNode, error) { return nil, fmt.Errorf("configuration required") } + id, err := peer.NewIdentity(cfg.Identity) + if err != nil { + return nil, err + } + d, err := makeDatastore(cfg.Datastore) if err != nil { return nil, err @@ -67,6 +72,7 @@ func NewIpfsNode(cfg *config.Config) (*IpfsNode, error) { n := &IpfsNode{ Config: cfg, + Identity: id, PeerMap: &peer.Map{}, Datastore: d, Blocks: bs, diff --git a/name/name.go b/name/name.go index 33c091b5962..9af73615cd3 100644 --- a/name/name.go +++ b/name/name.go @@ -24,8 +24,7 @@ func Resolve(name string) (mh.Multihash, error) { } if isB58 { // Is a base58 hash. - h, err := mh.FromB58String(name) - return h, err + return mh.FromB58String(name) } else if isPQ { // Is a Proquint identifier. return mh.Multihash(proquint.Decode(name)), nil } else { // Is a domain name. Hopefully. @@ -38,8 +37,7 @@ func Resolve(name string) (mh.Multihash, error) { var parts []string = strings.SplitN(txts[i], "=", 2) if len(parts) == 2 && parts[0] == "ipfs" { - h, err := mh.FromB58String(parts[1]) - return h, err + return mh.FromB58String(parts[1]) } } diff --git a/peer/peer.go b/peer/peer.go index e7c3af2b46d..e7154f31b95 100644 --- a/peer/peer.go +++ b/peer/peer.go @@ -4,8 +4,16 @@ import ( u "github.com/jbenet/go-ipfs/util" ma "github.com/jbenet/go-multiaddr" mh "github.com/jbenet/go-multihash" + config "github.com/jbenet/go-ipfs/config" "bytes" + "errors" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/sha1" + "crypto/sha256" + "crypto/rand" + "math/big" ) // ID is a byte slice representing the identity of a peer. @@ -23,7 +31,12 @@ type Map map[u.Key]*Peer // ID, and relevant Addresses. type Peer struct { ID ID + PubKey []byte Addresses []*ma.Multiaddr + + curve elliptic.Curve + hellman []byte + signing *ecdsa.PrivateKey } // Key returns the ID as a Key (string) for maps. @@ -52,3 +65,139 @@ func (p *Peer) NetAddress(n string) *ma.Multiaddr { } return nil } + +// Generates a shared secret key between us and the given public key. +func (p *Peer) Secret(pubKey []byte) ([]byte, error) { + // Verify and unpack node's public key. + curveSize := p.curve.Params().BitSize + + if len(pubKey) != (curveSize / 2) { + return nil, errors.New("Malformed public key.") + } + + bound := (curveSize / 8) + x := big.NewInt(0) + y := big.NewInt(0) + + x.SetBytes(pubKey[0:bound]) + y.SetBytes(pubKey[bound:bound * 2]) + + if !p.curve.IsOnCurve(x, y) { + return nil, errors.New("Invalid public key.") + } + + // Generate shared secret. + secret, _ := p.curve.ScalarMult(x, y, p.hellman) + + return secret.Bytes(), nil +} + +func (p *Peer) Sign(data []byte) ([]byte, error) { + var out bytes.Buffer + + hash := sha256.New() + hash.Write(data) + + r, s, err := ecdsa.Sign(rand.Reader, p.signing, hash.Sum(nil)) + if err != nil { + return nil, err + } + + out.Write(r.Bytes()) + out.Write(s.Bytes()) + + return out.Bytes(), nil +} + +func (p *Peer) Verify(pubKey, data, sig []byte) (bool, error) { + curveSize := p.curve.Params().BitSize + + // Verify and unpack public key. + if len(pubKey) != (curveSize / 2) { + return false, errors.New("Malformed public key.") + } + + bound1 := (curveSize / 8) + x := big.NewInt(0) + y := big.NewInt(0) + + x.SetBytes(pubKey[bound1 * 2:bound1 * 3]) + y.SetBytes(pubKey[bound1 * 3:]) + + parsedPubKey := &ecdsa.PublicKey{p.curve, x, y} + + // Verify and unpack signature. + if len(sig) != (curveSize / 4) { + return false, errors.New("Malformed signature.") + } + + bound2 := (curveSize / 8) + r := big.NewInt(0) + s := big.NewInt(0) + + r.SetBytes(sig[0:bound2]) + s.SetBytes(sig[bound2:]) + + // Verify signature. + hash := sha256.New() + hash.Write(data) + + ok := ecdsa.Verify(parsedPubKey, hash.Sum(nil), r, s) + + return ok, nil +} + +/** +* Generates a new, random peer identity. +* +* @return {Peer} +*/ +func NewIdentity(cfg *config.Identity) (*Peer, error) { + // Select curve given in config. + var curve elliptic.Curve + var pubKey bytes.Buffer + + switch cfg.Curve { + case 224: curve = elliptic.P224() + case 256: curve = elliptic.P256() + case 384: curve = elliptic.P384() + case 521: curve = elliptic.P521() + default: return nil, errors.New("Bad curve name in config.") + } + + // Generate a random ECDH keypair. + priv, x, y, err := elliptic.GenerateKey(curve, rand.Reader) + if err != nil { + return nil, err + } + + pubKey.Write(x.Bytes()) + pubKey.Write(y.Bytes()) + + // Generate a random ECDSA keypair. + signingPriv, err := ecdsa.GenerateKey(curve, rand.Reader) + if err != nil { + return nil, err + } + + pubKey.Write(signingPriv.PublicKey.X.Bytes()) + pubKey.Write(signingPriv.PublicKey.Y.Bytes()) + + // Generate peer ID + hash := sha1.New() // THIS NEEDS TO BE SHA256 + hash.Write(pubKey.Bytes()) + + id, err := mh.EncodeName(hash.Sum(nil), "sha1") + if err != nil { + return nil, err + } + + return &Peer{ + id, + pubKey.Bytes(), + []*ma.Multiaddr{}, + curve, + priv, + signingPriv, + }, nil +} From f3fd4414dcceb211fb2479bf69846d75ec7f02d8 Mon Sep 17 00:00:00 2001 From: Brendan Mc Date: Thu, 31 Jul 2014 17:46:36 -0400 Subject: [PATCH 4/5] Go fmt'd --- core/core.go | 8 +- namesys/namesys.go | 46 +++++++++ path/path.go | 16 ++-- peer/peer.go | 229 +++++++++++++++++++++++---------------------- 4 files changed, 176 insertions(+), 123 deletions(-) create mode 100644 namesys/namesys.go diff --git a/core/core.go b/core/core.go index db6f7d626f3..85d62a07fa5 100644 --- a/core/core.go +++ b/core/core.go @@ -53,10 +53,10 @@ func NewIpfsNode(cfg *config.Config) (*IpfsNode, error) { return nil, fmt.Errorf("configuration required") } - id, err := peer.NewIdentity(cfg.Identity) - if err != nil { - return nil, err - } + id, err := peer.NewIdentity(cfg.Identity) + if err != nil { + return nil, err + } d, err := makeDatastore(cfg.Datastore) if err != nil { diff --git a/namesys/namesys.go b/namesys/namesys.go new file mode 100644 index 00000000000..0aa85f47a70 --- /dev/null +++ b/namesys/namesys.go @@ -0,0 +1,46 @@ +package naming + +import ( + "errors" + proquint "github.com/Bren2010/proquint" + mh "github.com/jbenet/go-multihash" + "net" + "regexp" + "strings" +) + +func Resolve(name string) (mh.Multihash, error) { + b58Exp := "^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]*$" + pqExp := "^([abdfghijklmnoprstuvz]{5}-)*[abdfghijklmnoprstuvz]{5}$" + + isB58, err := regexp.MatchString(b58Exp, name) + if err != nil { + return nil, err + } + + isPQ, err := regexp.MatchString(pqExp, name) + if err != nil { + return nil, err + } + + if isB58 { // Is a base58 hash. + return mh.FromB58String(name) + } else if isPQ { // Is a Proquint identifier. + return mh.Multihash(proquint.Decode(name)), nil + } else { // Is a domain name. Hopefully. + txts, err := net.LookupTXT(name) + if err != nil { + return nil, err + } + + for i := 0; i < len(txts); i++ { + var parts []string = strings.SplitN(txts[i], "=", 2) + + if len(parts) == 2 && parts[0] == "ipfs" { + return mh.FromB58String(parts[1]) + } + } + + return nil, errors.New("Could not resolve IPNS.") + } +} diff --git a/path/path.go b/path/path.go index fe12a9d5f2d..1034521cb72 100644 --- a/path/path.go +++ b/path/path.go @@ -1,10 +1,10 @@ package path import ( + name "./../name" "fmt" merkledag "github.com/jbenet/go-ipfs/merkledag" u "github.com/jbenet/go-ipfs/util" - name "github.com/jbenet/go-ipfs/name" "path" "strings" ) @@ -33,15 +33,15 @@ func (s *Resolver) ResolvePath(fpath string) (*merkledag.Node, error) { return nil, fmt.Errorf("ipfs path must contain at least one component") } - h, err := name.Resolve(parts[0]) - if err != nil { - return nil, err + h, err := name.Resolve(parts[0]) + if err != nil { + return nil, err } - nd, err := s.DAG.Get(u.Key(h)) - if err != nil { - return nil, err - } + nd, err := s.DAG.Get(u.Key(h)) + if err != nil { + return nil, err + } return s.ResolveLinks(nd, parts[1:]) } diff --git a/peer/peer.go b/peer/peer.go index e7154f31b95..52838c24406 100644 --- a/peer/peer.go +++ b/peer/peer.go @@ -1,18 +1,18 @@ package peer import ( + config "github.com/jbenet/go-ipfs/config" u "github.com/jbenet/go-ipfs/util" ma "github.com/jbenet/go-multiaddr" mh "github.com/jbenet/go-multihash" - config "github.com/jbenet/go-ipfs/config" "bytes" - "errors" "crypto/ecdsa" "crypto/elliptic" + "crypto/rand" "crypto/sha1" "crypto/sha256" - "crypto/rand" + "errors" "math/big" ) @@ -34,9 +34,9 @@ type Peer struct { PubKey []byte Addresses []*ma.Multiaddr - curve elliptic.Curve - hellman []byte - signing *ecdsa.PrivateKey + curve elliptic.Curve + hellman []byte + signing *ecdsa.PrivateKey } // Key returns the ID as a Key (string) for maps. @@ -68,136 +68,143 @@ func (p *Peer) NetAddress(n string) *ma.Multiaddr { // Generates a shared secret key between us and the given public key. func (p *Peer) Secret(pubKey []byte) ([]byte, error) { - // Verify and unpack node's public key. - curveSize := p.curve.Params().BitSize - - if len(pubKey) != (curveSize / 2) { - return nil, errors.New("Malformed public key.") - } - - bound := (curveSize / 8) - x := big.NewInt(0) - y := big.NewInt(0) - - x.SetBytes(pubKey[0:bound]) - y.SetBytes(pubKey[bound:bound * 2]) - - if !p.curve.IsOnCurve(x, y) { - return nil, errors.New("Invalid public key.") - } - - // Generate shared secret. - secret, _ := p.curve.ScalarMult(x, y, p.hellman) - - return secret.Bytes(), nil + // Verify and unpack node's public key. + curveSize := p.curve.Params().BitSize + + if len(pubKey) != (curveSize / 2) { + return nil, errors.New("Malformed public key.") + } + + bound := (curveSize / 8) + x := big.NewInt(0) + y := big.NewInt(0) + + x.SetBytes(pubKey[0:bound]) + y.SetBytes(pubKey[bound : bound*2]) + + if !p.curve.IsOnCurve(x, y) { + return nil, errors.New("Invalid public key.") + } + + // Generate shared secret. + secret, _ := p.curve.ScalarMult(x, y, p.hellman) + + return secret.Bytes(), nil } +// Signs a given piece of data. func (p *Peer) Sign(data []byte) ([]byte, error) { - var out bytes.Buffer + var out bytes.Buffer - hash := sha256.New() - hash.Write(data) + hash := sha256.New() + hash.Write(data) - r, s, err := ecdsa.Sign(rand.Reader, p.signing, hash.Sum(nil)) - if err != nil { - return nil, err - } + r, s, err := ecdsa.Sign(rand.Reader, p.signing, hash.Sum(nil)) + if err != nil { + return nil, err + } - out.Write(r.Bytes()) - out.Write(s.Bytes()) + out.Write(r.Bytes()) + out.Write(s.Bytes()) - return out.Bytes(), nil + return out.Bytes(), nil } +// Verifies a signature on a given piece of data. func (p *Peer) Verify(pubKey, data, sig []byte) (bool, error) { - curveSize := p.curve.Params().BitSize + curveSize := p.curve.Params().BitSize - // Verify and unpack public key. - if len(pubKey) != (curveSize / 2) { - return false, errors.New("Malformed public key.") - } + // Verify and unpack public key. + if len(pubKey) != (curveSize / 2) { + return false, errors.New("Malformed public key.") + } - bound1 := (curveSize / 8) - x := big.NewInt(0) - y := big.NewInt(0) + bound1 := (curveSize / 8) + x := big.NewInt(0) + y := big.NewInt(0) - x.SetBytes(pubKey[bound1 * 2:bound1 * 3]) - y.SetBytes(pubKey[bound1 * 3:]) + x.SetBytes(pubKey[bound1*2 : bound1*3]) + y.SetBytes(pubKey[bound1*3:]) - parsedPubKey := &ecdsa.PublicKey{p.curve, x, y} + parsedPubKey := &ecdsa.PublicKey{p.curve, x, y} - // Verify and unpack signature. - if len(sig) != (curveSize / 4) { - return false, errors.New("Malformed signature.") - } + // Verify and unpack signature. + if len(sig) != (curveSize / 4) { + return false, errors.New("Malformed signature.") + } - bound2 := (curveSize / 8) - r := big.NewInt(0) - s := big.NewInt(0) + bound2 := (curveSize / 8) + r := big.NewInt(0) + s := big.NewInt(0) - r.SetBytes(sig[0:bound2]) - s.SetBytes(sig[bound2:]) + r.SetBytes(sig[0:bound2]) + s.SetBytes(sig[bound2:]) - // Verify signature. - hash := sha256.New() - hash.Write(data) + // Verify signature. + hash := sha256.New() + hash.Write(data) - ok := ecdsa.Verify(parsedPubKey, hash.Sum(nil), r, s) + ok := ecdsa.Verify(parsedPubKey, hash.Sum(nil), r, s) - return ok, nil + return ok, nil } /** * Generates a new, random peer identity. * * @return {Peer} -*/ + */ func NewIdentity(cfg *config.Identity) (*Peer, error) { - // Select curve given in config. - var curve elliptic.Curve - var pubKey bytes.Buffer - - switch cfg.Curve { - case 224: curve = elliptic.P224() - case 256: curve = elliptic.P256() - case 384: curve = elliptic.P384() - case 521: curve = elliptic.P521() - default: return nil, errors.New("Bad curve name in config.") - } - - // Generate a random ECDH keypair. - priv, x, y, err := elliptic.GenerateKey(curve, rand.Reader) - if err != nil { - return nil, err - } - - pubKey.Write(x.Bytes()) - pubKey.Write(y.Bytes()) - - // Generate a random ECDSA keypair. - signingPriv, err := ecdsa.GenerateKey(curve, rand.Reader) - if err != nil { - return nil, err - } - - pubKey.Write(signingPriv.PublicKey.X.Bytes()) - pubKey.Write(signingPriv.PublicKey.Y.Bytes()) - - // Generate peer ID - hash := sha1.New() // THIS NEEDS TO BE SHA256 - hash.Write(pubKey.Bytes()) - - id, err := mh.EncodeName(hash.Sum(nil), "sha1") - if err != nil { - return nil, err - } - - return &Peer{ - id, - pubKey.Bytes(), - []*ma.Multiaddr{}, - curve, - priv, - signingPriv, - }, nil + // Select curve given in config. + var curve elliptic.Curve + var pubKey bytes.Buffer + + switch cfg.Curve { + case 224: + curve = elliptic.P224() + case 256: + curve = elliptic.P256() + case 384: + curve = elliptic.P384() + case 521: + curve = elliptic.P521() + default: + return nil, errors.New("Bad curve name in config.") + } + + // Generate a random ECDH keypair. + priv, x, y, err := elliptic.GenerateKey(curve, rand.Reader) + if err != nil { + return nil, err + } + + pubKey.Write(x.Bytes()) + pubKey.Write(y.Bytes()) + + // Generate a random ECDSA keypair. + signingPriv, err := ecdsa.GenerateKey(curve, rand.Reader) + if err != nil { + return nil, err + } + + pubKey.Write(signingPriv.PublicKey.X.Bytes()) + pubKey.Write(signingPriv.PublicKey.Y.Bytes()) + + // Generate peer ID + hash := sha1.New() // THIS NEEDS TO BE SHA256 + hash.Write(pubKey.Bytes()) + + id, err := mh.EncodeName(hash.Sum(nil), "sha1") + if err != nil { + return nil, err + } + + return &Peer{ + id, + pubKey.Bytes(), + []*ma.Multiaddr{}, + curve, + priv, + signingPriv, + }, nil } From 955eb51791bd710cbfbfb51a3074014908482527 Mon Sep 17 00:00:00 2001 From: Brendan Mc Date: Thu, 31 Jul 2014 20:35:39 -0400 Subject: [PATCH 5/5] Edits from jbenet's comments - Delete name.go - Update path.go - Update namesys.go --- name/name.go | 46 ---------------------------------------------- namesys/namesys.go | 2 +- path/path.go | 2 +- 3 files changed, 2 insertions(+), 48 deletions(-) delete mode 100644 name/name.go diff --git a/name/name.go b/name/name.go deleted file mode 100644 index 9af73615cd3..00000000000 --- a/name/name.go +++ /dev/null @@ -1,46 +0,0 @@ -package naming - -import ( - "net" - "strings" - "regexp" - "errors" - proquint "github.com/Bren2010/proquint" - mh "github.com/jbenet/go-multihash" -) - -func Resolve(name string) (mh.Multihash, error) { - b58Exp := "^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]*$" - pqExp := "^([abdfghijklmnoprstuvz]{5}-)*[abdfghijklmnoprstuvz]{5}$" - - isB58, err := regexp.MatchString(b58Exp, name) - if err != nil { - return nil, err - } - - isPQ, err := regexp.MatchString(pqExp, name) - if err != nil { - return nil, err - } - - if isB58 { // Is a base58 hash. - return mh.FromB58String(name) - } else if isPQ { // Is a Proquint identifier. - return mh.Multihash(proquint.Decode(name)), nil - } else { // Is a domain name. Hopefully. - txts, err := net.LookupTXT(name) - if err != nil { - return nil, err - } - - for i := 0; i < len(txts); i++ { - var parts []string = strings.SplitN(txts[i], "=", 2) - - if len(parts) == 2 && parts[0] == "ipfs" { - return mh.FromB58String(parts[1]) - } - } - - return nil, errors.New("Could not resolve IPNS.") - } -} diff --git a/namesys/namesys.go b/namesys/namesys.go index 0aa85f47a70..85a70aac789 100644 --- a/namesys/namesys.go +++ b/namesys/namesys.go @@ -1,4 +1,4 @@ -package naming +package namesys import ( "errors" diff --git a/path/path.go b/path/path.go index 1034521cb72..ddcbeedb1b7 100644 --- a/path/path.go +++ b/path/path.go @@ -1,7 +1,7 @@ package path import ( - name "./../name" + namesys "github.com/jbenet/go-ipfs/namesys" "fmt" merkledag "github.com/jbenet/go-ipfs/merkledag" u "github.com/jbenet/go-ipfs/util"