Skip to content
This repository has been archived by the owner on Dec 7, 2019. It is now read-only.

change how we calculate inline peer IDs. #30

Merged
merged 2 commits into from
Mar 22, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,16 @@
},
{
"author": "whyrusleeping",
"hash": "QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo",
"hash": "Qmb9aAJwV1mDc5iPNtVuzVvsNiKA6kkDpZspMUgVfXPVc8",
"name": "go-libp2p-crypto",
"version": "1.5.0"
"version": "1.6.0"
},
{
"author": "multiformats",
"hash": "QmZyZDi491cCNTLfAhwcaDii2Kg4pwKRkhqQzURGDvY6ua",
"name": "go-multihash",
"version": "1.0.7"
},
{
"author": "whyrusleeping",
"hash": "QmNhVCV7kgAqW6oh6n8m9myxT2ksGPhVZnHkzkBvR5qg2d",
"name": "go-multicodec-packed",
"version": "0.1.0"
},
{
"author": "mr-tron",
"hash": "QmWFAMPqsEyUX7gDUsRVmMWz59FxSpJ1b2v6bJ1yYzo7jY",
Expand Down
110 changes: 24 additions & 86 deletions peer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,28 @@
package peer

import (
"encoding/binary"
"encoding/hex"
"errors"
"fmt"
"strings"

logging "github.com/ipfs/go-log" // ID represents the identity of a peer.
ic "github.com/libp2p/go-libp2p-crypto"
b58 "github.com/mr-tron/base58/base58"
mc "github.com/multiformats/go-multicodec-packed"
mh "github.com/multiformats/go-multihash"
)

// MaxInlineKeyLength is the maximum length a key can be for it to be inlined in
// the peer ID.
//
// * When `len(pubKey.Bytes()) <= MaxInlineKeyLength`, the peer ID is the
// identity multihash hash of the public key.
// * When `len(pubKey.Bytes()) > MaxInlineKeyLength`, the peer ID is the
// sha2-256 multihash of the public key.
const MaxInlineKeyLength = 42

var log = logging.Logger("peer")

// ID is a libp2p peer identity.
type ID string

// Pretty returns a b58-encoded string of the ID
Expand Down Expand Up @@ -66,77 +73,23 @@ func (id ID) MatchesPublicKey(pk ic.PubKey) bool {
return oid == id
}

var MultihashDecodeErr = errors.New("unable to decode multihash")
var MultihashCodecErr = errors.New("unexpected multihash codec")
var MultihashLengthErr = errors.New("unexpected multihash length")
var CodePrefixErr = errors.New("unexpected code prefix")

func (id ID) ExtractEd25519PublicKey() (ic.PubKey, error) {
// ed25519 pubkey identity format
// <identity mc><length (2 + 32 = 34)><ed25519-pub mc><ed25519 pubkey>
// <0x00 ><0x22 ><0xed01 ><ed25519 pubkey>

var nilPubKey ic.PubKey

// Decode multihash
// ExtractPublicKey attempts to extract the public key from an ID
//
// This method returns nil, nil if the peer ID looks valid but it can't extract
// the public key.
func (id ID) ExtractPublicKey() (ic.PubKey, error) {
decoded, err := mh.Decode([]byte(id))
if err != nil {
return nilPubKey, MultihashDecodeErr
return nil, err
}

// Check ID multihash codec
if decoded.Code != mh.ID {
return nilPubKey, MultihashCodecErr
}

// Check multihash length
if decoded.Length != 2+32 {
return nilPubKey, MultihashLengthErr
}

// Split prefix
code, pubKeyBytes := mc.SplitPrefix(decoded.Digest)

// Check ed25519 code
if code != mc.Ed25519Pub {
return nilPubKey, CodePrefixErr
}

// Unmarshall public key
pubKey, err := ic.UnmarshalEd25519PublicKey(pubKeyBytes)
if err != nil {
// Should never occur because of the check decoded.Length != 2+32
return nilPubKey, fmt.Errorf("Unexpected error unmarshalling Ed25519 public key")
}

return pubKey, nil
}

// ExtractPublicKey attempts to extract the public key from an ID
func (id ID) ExtractPublicKey() ic.PubKey {
var pk ic.PubKey

// Try extract ed25519 pubkey
pk, err := id.ExtractEd25519PublicKey()
if err != nil {
log.Info(err, id)
}

if pk != nil {
return pk
return nil, nil
}

// Try extract other type of pubkey
/*pk, err = id.Extract...PublicKey()
pk, err := ic.UnmarshalPublicKey(decoded.Digest)
if err != nil {
log.Error(err, id)
return nil, err
}

if pk != nil {
return pk
}*/

return pk
return pk, nil
}

// IDFromString cast a string to ID type, and validate
Expand Down Expand Up @@ -191,26 +144,11 @@ func IDFromPublicKey(pk ic.PubKey) (ID, error) {
if err != nil {
return "", err
}
hash, _ := mh.Sum(b, mh.SHA2_256, -1)
return ID(hash), nil
}

// IDFromEd25519PublicKey returns the Peer ID corresponding to Id25519 pk
func IDFromEd25519PublicKey(pk ic.PubKey) (ID, error) {
b, err := pk.Bytes()
if err != nil {
return "", err
}

// Build the ed25519 public key multi-codec
Ed25519PubMultiCodec := make([]byte, 2)
binary.PutUvarint(Ed25519PubMultiCodec, uint64(mc.Ed25519Pub))

hash, err := mh.Sum(append(Ed25519PubMultiCodec, b[len(b)-32:]...), mh.ID, 34)
if err != nil {
return "", err
var alg uint64 = mh.SHA2_256
if len(b) <= MaxInlineKeyLength {
alg = mh.ID
}

hash, _ := mh.Sum(b, alg, -1)
return ID(hash), nil
}

Expand Down
56 changes: 26 additions & 30 deletions peer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,51 +160,47 @@ func TestPublicKeyExtraction(t *testing.T) {
t.Fatal(err)
}

id, err := IDFromEd25519PublicKey(originalPub)
id, err := IDFromPublicKey(originalPub)
if err != nil {
t.Fatal(err)
}

extractedPub := id.ExtractPublicKey()
if !originalPub.Equals(extractedPub) {
extractedPub, err := id.ExtractPublicKey()
if err != nil {
t.Fatal(err)
}
if extractedPub == nil {
t.Fatal("failed to extract public key")
}
if !originalPub.Equals(extractedPub) {
t.Fatal("extracted public key doesn't match")
}

// Test invalid multihash (invariant of the type of public key)
if ID("").ExtractPublicKey() != nil {
t.Fatal("Expecting a nil public key")
pk, err := ID("").ExtractPublicKey()
if err == nil {
t.Fatal("expected an error")
}
if pk != nil {
t.Fatal("expected a nil public key")
}
}

func TestEd25519PublicKeyExtraction(t *testing.T) {
randomKey := make([]byte, 32)
_, err := rand.Read(randomKey)
// Shouldn't work for, e.g. RSA keys (too large)

_, rsaPub, err := ic.GenerateKeyPair(ic.RSA, 2048)
if err != nil {
t.Fatal(err)
}

// Error case 1: Invalid multihash
_, err = ID("").ExtractEd25519PublicKey()
if err != MultihashDecodeErr {
t.Fatal("Error case 1: Expected an error")
}

// Error case 2: Non-ID multihash
_, err = ID(append([]byte{0x01 /* != 0x00 (id) */, 0x22, 0xed, 0x01}, randomKey...)).ExtractEd25519PublicKey()
if err != MultihashCodecErr {
t.Fatal("Error case 2: Expecting an error")
rsaId, err := IDFromPublicKey(rsaPub)
if err != nil {
t.Fatal(err)
}

// Error case 3: Non-34 multihash length
_, err = ID(append([]byte{0x00, 0x23 /* 35 = 34 + 1 != 35 */, 0xed, 0x01, 0x00 /* extra byte */}, randomKey...)).ExtractEd25519PublicKey()
if err != MultihashLengthErr {
t.Fatal("Error case 3: Expecting an error")
extractedRsaPub, err := rsaId.ExtractPublicKey()
if err != nil {
t.Fatal(err)
}

// Error case 4: Non-ed25519 code
_, err = ID(append([]byte{0x00, 0x22, 0xef /* != 0xed */, 0x01}, randomKey...)).ExtractEd25519PublicKey()
if err != CodePrefixErr {
t.Fatal("Error case 4: Expecting an error")
if extractedRsaPub != nil {
t.Fatal("expected to fail to extract public key from rsa ID")
}
}

Expand Down