diff --git a/document/document_test.go b/document/document_test.go index e28364b..bd95767 100644 --- a/document/document_test.go +++ b/document/document_test.go @@ -23,11 +23,11 @@ func TestRoundTrip(t *testing.T) { strDoc: ed25519Doc, assertion: func(t *testing.T, doc *Document) { require.Equal(t, "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", doc.ID()) - require.Equal(t, ed25519vm.Type, doc.Authentication()[0].Type()) - require.Equal(t, ed25519vm.Type, doc.Assertion()[0].Type()) - require.Equal(t, x25519vm.Type, doc.KeyAgreement()[0].Type()) - require.Equal(t, ed25519vm.Type, doc.CapabilityInvocation()[0].Type()) - require.Equal(t, ed25519vm.Type, doc.CapabilityDelegation()[0].Type()) + require.Equal(t, ed25519vm.Type2020, doc.Authentication()[0].Type()) + require.Equal(t, ed25519vm.Type2020, doc.Assertion()[0].Type()) + require.Equal(t, x25519vm.Type2020, doc.KeyAgreement()[0].Type()) + require.Equal(t, ed25519vm.Type2020, doc.CapabilityInvocation()[0].Type()) + require.Equal(t, ed25519vm.Type2020, doc.CapabilityDelegation()[0].Type()) }, }, { diff --git a/verifications/json.go b/verifications/json.go index 382b9de..8c6c1f4 100644 --- a/verifications/json.go +++ b/verifications/json.go @@ -8,6 +8,8 @@ import ( "github.com/INFURA/go-did/verifications/ed25519" "github.com/INFURA/go-did/verifications/jsonwebkey" "github.com/INFURA/go-did/verifications/multikey" + p256vm "github.com/INFURA/go-did/verifications/p256" + secp256k1vm "github.com/INFURA/go-did/verifications/secp256k1" "github.com/INFURA/go-did/verifications/x25519" ) @@ -21,11 +23,19 @@ func UnmarshalJSON(data []byte) (did.VerificationMethod, error) { var res did.VerificationMethod switch aux.Type { - case ed25519vm.Type: + case ed25519vm.Type2018: + res = &ed25519vm.VerificationKey2018{} + case ed25519vm.Type2020: res = &ed25519vm.VerificationKey2020{} case multikey.Type: res = &multikey.MultiKey{} - case x25519vm.Type: + case p256vm.Type2021: + res = &p256vm.Key2021{} + case secp256k1vm.Type: + res = &secp256k1vm.VerificationKey2019{} + case x25519vm.Type2019: + res = &x25519vm.KeyAgreementKey2019{} + case x25519vm.Type2020: res = &x25519vm.KeyAgreementKey2020{} case jsonwebkey.Type: res = &jsonwebkey.JsonWebKey2020{} diff --git a/verifications/secp256k1/key2021.go b/verifications/secp256k1/key2021.go new file mode 100644 index 0000000..15146c5 --- /dev/null +++ b/verifications/secp256k1/key2021.go @@ -0,0 +1,114 @@ +package secp256k1vm + +import ( + "encoding/json" + "errors" + "fmt" + + "github.com/mr-tron/base58" + + "github.com/INFURA/go-did" + "github.com/INFURA/go-did/crypto" + "github.com/INFURA/go-did/crypto/secp256k1" +) + +// Specification: https://w3c-ccg.github.io/lds-ecdsa-secp256k1-2019/ + +const ( + JsonLdContext = "https://w3id.org/security/suites/secp256k1-2019/v1" + Type = "EcdsaSecp256k1VerificationKey2019" +) + +var _ did.VerificationMethodSignature = &VerificationKey2019{} +var _ did.VerificationMethodKeyAgreement = &VerificationKey2019{} + +type VerificationKey2019 struct { + id string + pubkey *secp256k1.PublicKey + controller string +} + +func NewVerificationKey2019(id string, pubkey *secp256k1.PublicKey, controller did.DID) *VerificationKey2019 { + return &VerificationKey2019{ + id: id, + pubkey: pubkey, + controller: controller.String(), + } +} + +func (vm VerificationKey2019) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + ID string `json:"id"` + Type string `json:"type"` + Controller string `json:"controller"` + PublicKeyBase58 string `json:"publicKeyBase58"` + }{ + ID: vm.ID(), + Type: vm.Type(), + Controller: vm.Controller(), + PublicKeyBase58: base58.Encode(vm.pubkey.ToBytes()), + }) +} + +func (vm *VerificationKey2019) UnmarshalJSON(bytes []byte) error { + aux := struct { + ID string `json:"id"` + Type string `json:"type"` + Controller string `json:"controller"` + PublicKeyBase58 string `json:"publicKeyBase58"` + }{} + err := json.Unmarshal(bytes, &aux) + if err != nil { + return err + } + if aux.Type != vm.Type() { + return errors.New("invalid type") + } + vm.id = aux.ID + if len(vm.id) == 0 { + return errors.New("invalid id") + } + vm.controller = aux.Controller + if !did.HasValidDIDSyntax(vm.controller) { + return errors.New("invalid controller") + } + + pubBytes, err := base58.Decode(aux.PublicKeyBase58) + if err != nil { + return fmt.Errorf("invalid publicKeyBase58: %w", err) + } + vm.pubkey, err = secp256k1.PublicKeyFromBytes(pubBytes) + if err != nil { + return fmt.Errorf("invalid publicKeyBase58: %w", err) + } + + return nil +} + +func (vm VerificationKey2019) ID() string { + return vm.id +} + +func (vm VerificationKey2019) Type() string { + return Type +} + +func (vm VerificationKey2019) Controller() string { + return vm.controller +} + +func (vm VerificationKey2019) JsonLdContext() string { + return JsonLdContext +} + +func (vm VerificationKey2019) Verify(data []byte, sig []byte) (bool, error) { + return vm.pubkey.VerifyBytes(data, sig), nil +} + +func (vm VerificationKey2019) PrivateKeyIsCompatible(local crypto.PrivateKeyKeyExchange) bool { + return local.PublicKeyIsCompatible(vm.pubkey) +} + +func (vm VerificationKey2019) KeyExchange(local crypto.PrivateKeyKeyExchange) ([]byte, error) { + return local.KeyExchange(vm.pubkey) +} diff --git a/verifications/secp256k1/key2021_test.go b/verifications/secp256k1/key2021_test.go new file mode 100644 index 0000000..19515e0 --- /dev/null +++ b/verifications/secp256k1/key2021_test.go @@ -0,0 +1,27 @@ +package secp256k1vm_test + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/require" + + secp256k1vm "github.com/INFURA/go-did/verifications/secp256k1" +) + +func TestJsonRoundTrip(t *testing.T) { + data := `{ + "id": "did:key:zQ3shadCps5JLAHcZiuX5YUtWHHL8ysBJqFLWvjZDKAWUBGzy#zQ3shadCps5JLAHcZiuX5YUtWHHL8ysBJqFLWvjZDKAWUBGzy", + "type": "EcdsaSecp256k1VerificationKey2019", + "controller": "did:key:zQ3shadCps5JLAHcZiuX5YUtWHHL8ysBJqFLWvjZDKAWUBGzy", + "publicKeyBase58": "pg3p1vprqePgUoqfAQ1TTgxhL6zLYhHyzooR1pqLxo9F" + }` + + var mk secp256k1vm.VerificationKey2019 + err := json.Unmarshal([]byte(data), &mk) + require.NoError(t, err) + + bytes, err := json.Marshal(mk) + require.NoError(t, err) + require.JSONEq(t, data, string(bytes)) +}