diff --git a/did/crypto.go b/did/crypto.go index 0947322..172065d 100644 --- a/did/crypto.go +++ b/did/crypto.go @@ -37,3 +37,12 @@ func FromPubKey(pubKey crypto.PubKey) (DID, error) { key: true, }, nil } + +func ToPubKey(s string) (crypto.PubKey, error) { + id, err := Parse(s) + if err != nil { + return nil, err + } + + return id.PubKey() +} diff --git a/did/crypto_test.go b/did/crypto_test.go index d49657a..64723bd 100644 --- a/did/crypto_test.go +++ b/did/crypto_test.go @@ -1,33 +1,51 @@ package did_test import ( - "bytes" - "encoding/binary" "testing" "github.com/libp2p/go-libp2p/core/crypto" - "github.com/multiformats/go-multicodec" "github.com/stretchr/testify/require" "github.com/ucan-wg/go-ucan/did" ) +const ( + exampleDIDStr = "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" + examplePubKeyStr = "Lm/M42cB3HkUiODQsXRcweM6TByfzEHGO9ND274JcOY=" +) + func TestFromPubKey(t *testing.T) { t.Parallel() - const example = "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" - - id, err := did.Parse(example) + id, err := did.FromPubKey(examplePubKey(t)) require.NoError(t, err) - - buf := bytes.NewBuffer(id.Bytes()) - - code, err := binary.ReadUvarint(buf) - require.NoError(t, err) - require.Equal(t, uint64(multicodec.Ed25519Pub), code) - - pubKey, err := crypto.UnmarshalEd25519PublicKey(buf.Bytes()) - require.NoError(t, err) - - id2, err := did.FromPubKey(pubKey) - require.Equal(t, id, id2) + require.Equal(t, exampleDID(t), id) +} + +func TestToPubKey(t *testing.T) { + t.Parallel() + + pubKey, err := did.ToPubKey(exampleDIDStr) + require.NoError(t, err) + require.Equal(t, examplePubKey(t), pubKey) +} + +func exampleDID(t *testing.T) did.DID { + t.Helper() + + id, err := did.Parse(exampleDIDStr) + require.NoError(t, err) + + return id +} + +func examplePubKey(t *testing.T) crypto.PubKey { + t.Helper() + + pubKeyCfg, err := crypto.ConfigDecodeKey(examplePubKeyStr) + require.NoError(t, err) + + pubKey, err := crypto.UnmarshalEd25519PublicKey(pubKeyCfg) + require.NoError(t, err) + + return pubKey } diff --git a/did/did.go b/did/did.go index 1b32a60..78dfd60 100644 --- a/did/did.go +++ b/did/did.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + crypto "github.com/libp2p/go-libp2p/core/crypto" mbase "github.com/multiformats/go-multibase" "github.com/multiformats/go-multicodec" varint "github.com/multiformats/go-varint" @@ -49,6 +50,24 @@ func (d DID) DID() DID { return d } +func (d DID) PubKey() (crypto.PubKey, error) { + if !d.key { + return nil, fmt.Errorf("unsupported did type: %s", d.String()) + } + + unmarshaler, ok := map[multicodec.Code]crypto.PubKeyUnmarshaller{ + multicodec.Ed25519Pub: crypto.UnmarshalEd25519PublicKey, + multicodec.RsaPub: crypto.UnmarshalRsaPublicKey, + multicodec.Secp256k1Pub: crypto.UnmarshalSecp256k1PublicKey, + multicodec.Es256: crypto.UnmarshalECDSAPublicKey, + }[multicodec.Code(d.code)] + if !ok { + return nil, fmt.Errorf("unsupported multicodec: %d", d.code) + } + + return unmarshaler(d.Bytes()[varint.UvarintSize(d.code):]) +} + // String formats the decentralized identity document (DID) as a string. func (d DID) String() string { if d.key {