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

Commit

Permalink
Merge pull request #15 from libp2p/JustinDrake-master
Browse files Browse the repository at this point in the history
ed25519 key extraction
  • Loading branch information
whyrusleeping committed Jul 11, 2017
2 parents 166a39e + 8693121 commit 378a7c1
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 2 deletions.
10 changes: 8 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,21 @@
},
{
"author": "whyrusleeping",
"hash": "QmP1DfoUjiWH2ZBo1PBH6FupdBucbDepx3HpWmEY6JMUpY",
"hash": "QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo",
"name": "go-libp2p-crypto",
"version": "1.4.2"
"version": "1.5.0"
},
{
"author": "multiformats",
"hash": "QmU9a9NV9RdPNwZQDYd5uKsm6N6LJLSvLbywDDYFbaaC6P",
"name": "go-multihash",
"version": "1.0.5"
},
{
"author": "whyrusleeping",
"hash": "QmNhVCV7kgAqW6oh6n8m9myxT2ksGPhVZnHkzkBvR5qg2d",
"name": "go-multicodec-packed",
"version": "0.1.0"
}
],
"gxVersion": "0.4.0",
Expand Down
95 changes: 95 additions & 0 deletions peer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
package peer

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

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

Expand Down Expand Up @@ -63,6 +66,79 @@ 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
decoded, err := mh.Decode([]byte(id))
if err != nil {
return nilPubKey, MultihashDecodeErr
}

// 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
}

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

return pk
}

// IDFromString cast a string to ID type, and validate
// the id to make sure it is a multihash.
func IDFromString(s string) (ID, error) {
Expand Down Expand Up @@ -119,6 +195,25 @@ func IDFromPublicKey(pk ic.PubKey) (ID, error) {
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
}

return ID(hash), nil
}

// IDFromPrivateKey returns the Peer ID corresponding to sk
func IDFromPrivateKey(sk ic.PrivKey) (ID, error) {
return IDFromPublicKey(sk.GetPublic())
Expand Down
56 changes: 56 additions & 0 deletions peer_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package peer_test

import (
"crypto/rand"
"encoding/base64"
"fmt"
"strings"
Expand Down Expand Up @@ -152,6 +153,61 @@ func TestIDMatchesPrivateKey(t *testing.T) {
test(man)
}

func TestPublicKeyExtraction(t *testing.T) {
// Happy path
_, originalPub, err := ic.GenerateEd25519Key(rand.Reader)
if err != nil {
t.Fatal(err)
}

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

extractedPub := id.ExtractPublicKey()
if !originalPub.Equals(extractedPub) {
t.Fatal(err)
}

// Test invalid multihash (invariant of the type of public key)
if ID("").ExtractPublicKey() != nil {
t.Fatal("Expecting a nil public key")
}
}

func TestEd25519PublicKeyExtraction(t *testing.T) {
randomKey := make([]byte, 32)
_, err := rand.Read(randomKey)
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")
}

// 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")
}

// 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")
}
}

var hpkpMan = `QmRK3JgmVEGiewxWbhpXLJyjWuGuLeSTMTndA1coMHEy5o`
var skManBytes = `
CAAS4AQwggJcAgEAAoGBAL7w+Wc4VhZhCdM/+Hccg5Nrf4q9NXWwJylbSrXz/unFS24wyk6pEk0zi3W
Expand Down

0 comments on commit 378a7c1

Please sign in to comment.