diff --git a/did/crypto.go b/did/crypto.go new file mode 100644 index 0000000..0947322 --- /dev/null +++ b/did/crypto.go @@ -0,0 +1,39 @@ +package did + +import ( + "errors" + + crypto "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/crypto/pb" + "github.com/multiformats/go-multicodec" + "github.com/multiformats/go-varint" +) + +func FromPrivKey(privKey crypto.PrivKey) (DID, error) { + return FromPubKey(privKey.GetPublic()) +} + +func FromPubKey(pubKey crypto.PubKey) (DID, error) { + code, ok := map[pb.KeyType]multicodec.Code{ + pb.KeyType_Ed25519: multicodec.Ed25519Pub, + pb.KeyType_RSA: multicodec.RsaPub, + pb.KeyType_Secp256k1: multicodec.Secp256k1Pub, + pb.KeyType_ECDSA: multicodec.Es256, + }[pubKey.Type()] + if !ok { + return Undef, errors.New("Blah") + } + + buf := varint.ToUvarint(uint64(code)) + + pubBytes, err := pubKey.Raw() + if err != nil { + return Undef, err + } + + return DID{ + str: string(append(buf, pubBytes...)), + code: uint64(code), + key: true, + }, nil +} diff --git a/did/crypto_test.go b/did/crypto_test.go new file mode 100644 index 0000000..98e38a9 --- /dev/null +++ b/did/crypto_test.go @@ -0,0 +1,33 @@ +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/v1/did" +) + +func TestFromPubKey(t *testing.T) { + t.Parallel() + + const example = "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" + + id, err := did.Parse(example) + 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) +} diff --git a/did/did.go b/did/did.go index 483485c..1b32a60 100644 --- a/did/did.go +++ b/did/did.go @@ -5,6 +5,7 @@ import ( "strings" mbase "github.com/multiformats/go-multibase" + "github.com/multiformats/go-multicodec" varint "github.com/multiformats/go-varint" ) @@ -13,12 +14,16 @@ const KeyPrefix = "did:key:" const DIDCore = 0x0d1d const Ed25519 = 0xed +const RSA = uint64(multicodec.RsaPub) var MethodOffset = varint.UvarintSize(uint64(DIDCore)) +// +// [did:key format]: https://w3c-ccg.github.io/did-method-key/ type DID struct { - key bool - str string + key bool + code uint64 + str string } // Undef can be used to represent a nil or undefined DID, using DID{} @@ -36,6 +41,10 @@ func (d DID) Bytes() []byte { return []byte(d.str) } +func (d DID) Code() uint64 { + return d.code +} + func (d DID) DID() DID { return d } @@ -54,8 +63,8 @@ func Decode(bytes []byte) (DID, error) { if err != nil { return Undef, err } - if code == Ed25519 { - return DID{str: string(bytes), key: true}, nil + if code == Ed25519 || code == RSA { + return DID{str: string(bytes), code: code, key: true}, nil } else if code == DIDCore { return DID{str: string(bytes)}, nil }