add support for JsonWebKey2020

This commit is contained in:
Michael Muré
2025-06-25 10:51:13 +02:00
committed by Michael Muré
parent 775b693cd0
commit 2809127a08
7 changed files with 493 additions and 18 deletions

View File

@@ -31,6 +31,14 @@ func PublicKeyFromBytes(b []byte) (*PublicKey, error) {
return (*PublicKey)(&ecdsa.PublicKey{Curve: elliptic.P256(), X: x, Y: y}), nil
}
// PublicKeyFromXY converts x and y coordinates into a PublicKey.
func PublicKeyFromXY(x, y *big.Int) (*PublicKey, error) {
if !elliptic.P256().IsOnCurve(x, y) {
return nil, fmt.Errorf("invalid P-256 public key")
}
return (*PublicKey)(&ecdsa.PublicKey{Curve: elliptic.P256(), X: x, Y: y}), nil
}
// PublicKeyFromPublicKeyMultibase decodes the public key from its Multibase form
func PublicKeyFromPublicKeyMultibase(multibase string) (*PublicKey, error) {
code, bytes, err := helpers.PublicKeyMultibaseDecode(multibase)

View File

@@ -8,11 +8,57 @@ import (
_ "github.com/INFURA/go-did/methods/did-key"
"github.com/INFURA/go-did/verifications/ed25519"
"github.com/INFURA/go-did/verifications/jsonwebkey"
"github.com/INFURA/go-did/verifications/x25519"
)
func TestRoundTrip(t *testing.T) {
strDoc := `
for _, tc := range []struct {
name string
strDoc string
assertion func(t *testing.T, doc *Document)
}{
{
name: "ed25519",
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())
},
},
{
name: "jsonWebKey",
strDoc: jsonWebKeyDoc,
assertion: func(t *testing.T, doc *Document) {
require.Equal(t, "did:example:123", doc.ID())
require.Len(t, doc.VerificationMethods(), 6)
require.Equal(t, jsonwebkey.Type, doc.verificationMethods["did:example:123#_Qq0UL2Fq651Q0Fjd6TvnYE-faHiOpRlPVQcY_-tA4A"].Type())
require.Equal(t, jsonwebkey.Type, doc.verificationMethods["did:example:123#4SZ-StXrp5Yd4_4rxHVTCYTHyt4zyPfN1fIuYsm6k3A"].Type())
require.Equal(t, jsonwebkey.Type, doc.verificationMethods["did:example:123#n4cQ-I_WkHMcwXBJa7IHkYu8CMfdNcZKnKsOrnHLpFs"].Type())
require.Equal(t, jsonwebkey.Type, doc.verificationMethods["did:example:123#_TKzHv2jFIyvdTGF1Dsgwngfdg3SH6TpDv0Ta1aOEkw"].Type())
require.Equal(t, jsonwebkey.Type, doc.verificationMethods["did:example:123#8wgRfY3sWmzoeAL-78-oALNvNj67ZlQxd1ss_NX1hZY"].Type())
require.Equal(t, jsonwebkey.Type, doc.verificationMethods["did:example:123#NjQ6Y_ZMj6IUK_XkgCDwtKHlNTUTVjEYOWZtxhp1n-E"].Type())
},
},
} {
t.Run(tc.name, func(t *testing.T) {
doc, err := FromJsonBytes([]byte(tc.strDoc))
require.NoError(t, err)
tc.assertion(t, doc)
roundtrip, err := json.Marshal(doc)
require.NoError(t, err)
require.JSONEq(t, tc.strDoc, string(roundtrip))
})
}
}
const ed25519Doc = `
{
"@context": [
"https://www.w3.org/ns/did/v1",
@@ -46,18 +92,108 @@ func TestRoundTrip(t *testing.T) {
}]
}
`
doc, err := FromJsonBytes([]byte(strDoc))
require.NoError(t, err)
// basic testing
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())
roundtrip, err := json.Marshal(doc)
require.NoError(t, err)
require.JSONEq(t, strDoc, string(roundtrip))
const jsonWebKeyDoc = `
{
"@context": ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/jws-2020/v1"],
"id": "did:example:123",
"verificationMethod": [
{
"id": "did:example:123#_Qq0UL2Fq651Q0Fjd6TvnYE-faHiOpRlPVQcY_-tA4A",
"type": "JsonWebKey2020",
"controller": "did:example:123",
"publicKeyJwk": {
"kty": "OKP",
"crv": "Ed25519",
"x": "VCpo2LMLhn6iWku8MKvSLg2ZAoC-nlOyPVQaO3FxVeQ"
}
},
{
"id": "did:example:123#4SZ-StXrp5Yd4_4rxHVTCYTHyt4zyPfN1fIuYsm6k3A",
"type": "JsonWebKey2020",
"controller": "did:example:123",
"publicKeyJwk": {
"kty": "EC",
"crv": "secp256k1",
"x": "Z4Y3NNOxv0J6tCgqOBFnHnaZhJF6LdulT7z8A-2D5_8",
"y": "i5a2NtJoUKXkLm6q8nOEu9WOkso1Ag6FTUT6k_LMnGk"
}
},
{
"id": "did:example:123#n4cQ-I_WkHMcwXBJa7IHkYu8CMfdNcZKnKsOrnHLpFs",
"type": "JsonWebKey2020",
"controller": "did:example:123",
"publicKeyJwk": {
"kty": "RSA",
"e": "AQAB",
"n": "omwsC1AqEk6whvxyOltCFWheSQvv1MExu5RLCMT4jVk9khJKv8JeMXWe3bWHatjPskdf2dlaGkW5QjtOnUKL742mvr4tCldKS3ULIaT1hJInMHHxj2gcubO6eEegACQ4QSu9LO0H-LM_L3DsRABB7Qja8HecpyuspW1Tu_DbqxcSnwendamwL52V17eKhlO4uXwv2HFlxufFHM0KmCJujIKyAxjD_m3q__IiHUVHD1tDIEvLPhG9Azsn3j95d-saIgZzPLhQFiKluGvsjrSkYU5pXVWIsV-B2jtLeeLC14XcYxWDUJ0qVopxkBvdlERcNtgF4dvW4X00EHj4vCljFw"
}
},
{
"id": "did:example:123#_TKzHv2jFIyvdTGF1Dsgwngfdg3SH6TpDv0Ta1aOEkw",
"type": "JsonWebKey2020",
"controller": "did:example:123",
"publicKeyJwk": {
"kty": "EC",
"crv": "P-256",
"x": "38M1FDts7Oea7urmseiugGW7tWc3mLpJh6rKe7xINZ8",
"y": "nDQW6XZ7b_u2Sy9slofYLlG03sOEoug3I0aAPQ0exs4"
}
},
{
"id": "did:example:123#8wgRfY3sWmzoeAL-78-oALNvNj67ZlQxd1ss_NX1hZY",
"type": "JsonWebKey2020",
"controller": "did:example:123",
"publicKeyJwk": {
"kty": "EC",
"crv": "P-384",
"x": "GnLl6mDti7a2VUIZP5w6pcRX8q5nvEIgB3Q_5RI2p9F_QVsaAlDN7IG68Jn0dS_F",
"y": "jq4QoAHKiIzezDp88s_cxSPXtuXYFliuCGndgU4Qp8l91xzD1spCmFIzQgVjqvcP"
}
},
{
"id": "did:example:123#NjQ6Y_ZMj6IUK_XkgCDwtKHlNTUTVjEYOWZtxhp1n-E",
"type": "JsonWebKey2020",
"controller": "did:example:123",
"publicKeyJwk": {
"kty": "EC",
"crv": "P-521",
"x": "AVlZG23LyXYwlbjbGPMxZbHmJpDSu-IvpuKigEN2pzgWtSo--Rwd-n78nrWnZzeDc187Ln3qHlw5LRGrX4qgLQ-y",
"y": "ANIbFeRdPHf1WYMCUjcPz-ZhecZFybOqLIJjVOlLETH7uPlyG0gEoMWnIZXhQVypPy_HtUiUzdnSEPAylYhHBTX2"
}
}
],
"authentication": [
"did:example:123#_Qq0UL2Fq651Q0Fjd6TvnYE-faHiOpRlPVQcY_-tA4A",
"did:example:123#4SZ-StXrp5Yd4_4rxHVTCYTHyt4zyPfN1fIuYsm6k3A",
"did:example:123#n4cQ-I_WkHMcwXBJa7IHkYu8CMfdNcZKnKsOrnHLpFs",
"did:example:123#_TKzHv2jFIyvdTGF1Dsgwngfdg3SH6TpDv0Ta1aOEkw",
"did:example:123#8wgRfY3sWmzoeAL-78-oALNvNj67ZlQxd1ss_NX1hZY",
"did:example:123#NjQ6Y_ZMj6IUK_XkgCDwtKHlNTUTVjEYOWZtxhp1n-E"
],
"assertionMethod": [
"did:example:123#_Qq0UL2Fq651Q0Fjd6TvnYE-faHiOpRlPVQcY_-tA4A",
"did:example:123#4SZ-StXrp5Yd4_4rxHVTCYTHyt4zyPfN1fIuYsm6k3A",
"did:example:123#n4cQ-I_WkHMcwXBJa7IHkYu8CMfdNcZKnKsOrnHLpFs",
"did:example:123#_TKzHv2jFIyvdTGF1Dsgwngfdg3SH6TpDv0Ta1aOEkw",
"did:example:123#8wgRfY3sWmzoeAL-78-oALNvNj67ZlQxd1ss_NX1hZY",
"did:example:123#NjQ6Y_ZMj6IUK_XkgCDwtKHlNTUTVjEYOWZtxhp1n-E"
],
"capabilityDelegation": [
"did:example:123#_Qq0UL2Fq651Q0Fjd6TvnYE-faHiOpRlPVQcY_-tA4A",
"did:example:123#4SZ-StXrp5Yd4_4rxHVTCYTHyt4zyPfN1fIuYsm6k3A",
"did:example:123#n4cQ-I_WkHMcwXBJa7IHkYu8CMfdNcZKnKsOrnHLpFs",
"did:example:123#_TKzHv2jFIyvdTGF1Dsgwngfdg3SH6TpDv0Ta1aOEkw",
"did:example:123#8wgRfY3sWmzoeAL-78-oALNvNj67ZlQxd1ss_NX1hZY",
"did:example:123#NjQ6Y_ZMj6IUK_XkgCDwtKHlNTUTVjEYOWZtxhp1n-E"
],
"capabilityInvocation": [
"did:example:123#_Qq0UL2Fq651Q0Fjd6TvnYE-faHiOpRlPVQcY_-tA4A",
"did:example:123#4SZ-StXrp5Yd4_4rxHVTCYTHyt4zyPfN1fIuYsm6k3A",
"did:example:123#n4cQ-I_WkHMcwXBJa7IHkYu8CMfdNcZKnKsOrnHLpFs",
"did:example:123#_TKzHv2jFIyvdTGF1Dsgwngfdg3SH6TpDv0Ta1aOEkw",
"did:example:123#8wgRfY3sWmzoeAL-78-oALNvNj67ZlQxd1ss_NX1hZY",
"did:example:123#NjQ6Y_ZMj6IUK_XkgCDwtKHlNTUTVjEYOWZtxhp1n-E"
]
}
`

View File

@@ -6,6 +6,7 @@ import (
"github.com/INFURA/go-did"
"github.com/INFURA/go-did/verifications/ed25519"
"github.com/INFURA/go-did/verifications/jsonwebkey"
"github.com/INFURA/go-did/verifications/multikey"
"github.com/INFURA/go-did/verifications/x25519"
)
@@ -26,6 +27,8 @@ func UnmarshalJSON(data []byte) (did.VerificationMethod, error) {
res = &multikey.MultiKey{}
case x25519vm.Type:
res = &x25519vm.KeyAgreementKey2020{}
case jsonwebkey.Type:
res = &jsonwebkey.JsonWebKey2020{}
default:
return nil, fmt.Errorf("unknown verification type: %s", aux.Type)
}

View File

@@ -0,0 +1,106 @@
package jsonwebkey
import (
"encoding/json"
"errors"
"github.com/INFURA/go-did"
"github.com/INFURA/go-did/crypto"
)
// Specification: https://www.w3.org/TR/vc-jws-2020/
const (
JsonLdContext = "https://w3id.org/security/suites/jws-2020/v1"
Type = "JsonWebKey2020"
)
var _ did.VerificationMethodSignature = &JsonWebKey2020{}
var _ did.VerificationMethodKeyAgreement = &JsonWebKey2020{}
type JsonWebKey2020 struct {
id string
pubkey crypto.PublicKey
controller string
}
func NewJsonWebKey2020(id string, pubkey crypto.PublicKey, controller did.DID) *JsonWebKey2020 {
return &JsonWebKey2020{
id: id,
pubkey: pubkey,
controller: controller.String(),
}
}
func (j JsonWebKey2020) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
ID string `json:"id"`
Type string `json:"type"`
Controller string `json:"controller"`
PublicKeyJWK jwk `json:"publicKeyJwk"`
}{
ID: j.ID(),
Type: j.Type(),
Controller: j.Controller(),
PublicKeyJWK: jwk{pubkey: j.pubkey},
})
}
func (j *JsonWebKey2020) UnmarshalJSON(bytes []byte) error {
aux := struct {
ID string `json:"id"`
Type string `json:"type"`
Controller string `json:"controller"`
PublicKeyJWK jwk `json:"publicKeyJwk"`
}{}
err := json.Unmarshal(bytes, &aux)
if err != nil {
return err
}
if aux.Type != j.Type() {
return errors.New("invalid type")
}
j.id = aux.ID
if len(j.id) == 0 {
return errors.New("invalid id")
}
j.controller = aux.Controller
if !did.HasValidDIDSyntax(j.controller) {
return errors.New("invalid controller")
}
j.pubkey = aux.PublicKeyJWK.pubkey
return nil
}
func (j JsonWebKey2020) ID() string {
return j.id
}
func (j JsonWebKey2020) Type() string {
return Type
}
func (j JsonWebKey2020) Controller() string {
return j.controller
}
func (j JsonWebKey2020) JsonLdContext() string {
return JsonLdContext
}
func (j JsonWebKey2020) Verify(data []byte, sig []byte) (bool, error) {
if pub, ok := j.pubkey.(crypto.SigningPublicKey); ok {
return pub.VerifyBytes(data, sig), nil
}
return false, errors.New("not a signing public key")
}
func (j JsonWebKey2020) PrivateKeyIsCompatible(local crypto.KeyExchangePrivateKey) bool {
return local.PublicKeyIsCompatible(j.pubkey)
}
func (j JsonWebKey2020) KeyExchange(local crypto.KeyExchangePrivateKey) ([]byte, error) {
return local.KeyExchange(j.pubkey)
}

View File

@@ -0,0 +1,102 @@
package jsonwebkey
import (
"encoding/json"
"testing"
"github.com/stretchr/testify/require"
)
func TestJsonRoundTrip(t *testing.T) {
for _, tc := range []struct {
name string
str string
}{
{
name: "did:example:123#_Qq0UL2Fq651Q0Fjd6TvnYE-faHiOpRlPVQcY_-tA4A",
str: `{
"id": "did:example:123#_Qq0UL2Fq651Q0Fjd6TvnYE-faHiOpRlPVQcY_-tA4A",
"type": "JsonWebKey2020",
"controller": "did:example:123",
"publicKeyJwk": {
"kty": "OKP",
"crv": "Ed25519",
"x": "VCpo2LMLhn6iWku8MKvSLg2ZAoC-nlOyPVQaO3FxVeQ"
}}`,
},
{
name: "did:example:123#4SZ-StXrp5Yd4_4rxHVTCYTHyt4zyPfN1fIuYsm6k3A",
str: `{
"id": "did:example:123#4SZ-StXrp5Yd4_4rxHVTCYTHyt4zyPfN1fIuYsm6k3A",
"type": "JsonWebKey2020",
"controller": "did:example:123",
"publicKeyJwk": {
"kty": "EC",
"crv": "secp256k1",
"x": "Z4Y3NNOxv0J6tCgqOBFnHnaZhJF6LdulT7z8A-2D5_8",
"y": "i5a2NtJoUKXkLm6q8nOEu9WOkso1Ag6FTUT6k_LMnGk"
}}`,
},
{
name: "did:example:123#n4cQ-I_WkHMcwXBJa7IHkYu8CMfdNcZKnKsOrnHLpFs",
str: `{
"id": "did:example:123#n4cQ-I_WkHMcwXBJa7IHkYu8CMfdNcZKnKsOrnHLpFs",
"type": "JsonWebKey2020",
"controller": "did:example:123",
"publicKeyJwk": {
"kty": "RSA",
"e": "AQAB",
"n": "omwsC1AqEk6whvxyOltCFWheSQvv1MExu5RLCMT4jVk9khJKv8JeMXWe3bWHatjPskdf2dlaGkW5QjtOnUKL742mvr4tCldKS3ULIaT1hJInMHHxj2gcubO6eEegACQ4QSu9LO0H-LM_L3DsRABB7Qja8HecpyuspW1Tu_DbqxcSnwendamwL52V17eKhlO4uXwv2HFlxufFHM0KmCJujIKyAxjD_m3q__IiHUVHD1tDIEvLPhG9Azsn3j95d-saIgZzPLhQFiKluGvsjrSkYU5pXVWIsV-B2jtLeeLC14XcYxWDUJ0qVopxkBvdlERcNtgF4dvW4X00EHj4vCljFw"
}}`,
},
{
name: "did:example:123#_TKzHv2jFIyvdTGF1Dsgwngfdg3SH6TpDv0Ta1aOEkw",
str: `{
"id": "did:example:123#_TKzHv2jFIyvdTGF1Dsgwngfdg3SH6TpDv0Ta1aOEkw",
"type": "JsonWebKey2020",
"controller": "did:example:123",
"publicKeyJwk": {
"kty": "EC",
"crv": "P-256",
"x": "38M1FDts7Oea7urmseiugGW7tWc3mLpJh6rKe7xINZ8",
"y": "nDQW6XZ7b_u2Sy9slofYLlG03sOEoug3I0aAPQ0exs4"
}}`,
},
{
name: "did:example:123#8wgRfY3sWmzoeAL-78-oALNvNj67ZlQxd1ss_NX1hZY",
str: `{
"id": "did:example:123#8wgRfY3sWmzoeAL-78-oALNvNj67ZlQxd1ss_NX1hZY",
"type": "JsonWebKey2020",
"controller": "did:example:123",
"publicKeyJwk": {
"kty": "EC",
"crv": "P-384",
"x": "GnLl6mDti7a2VUIZP5w6pcRX8q5nvEIgB3Q_5RI2p9F_QVsaAlDN7IG68Jn0dS_F",
"y": "jq4QoAHKiIzezDp88s_cxSPXtuXYFliuCGndgU4Qp8l91xzD1spCmFIzQgVjqvcP"
}}`,
},
{
name: "did:example:123#NjQ6Y_ZMj6IUK_XkgCDwtKHlNTUTVjEYOWZtxhp1n-E",
str: `{
"id": "did:example:123#NjQ6Y_ZMj6IUK_XkgCDwtKHlNTUTVjEYOWZtxhp1n-E",
"type": "JsonWebKey2020",
"controller": "did:example:123",
"publicKeyJwk": {
"kty": "EC",
"crv": "P-521",
"x": "AVlZG23LyXYwlbjbGPMxZbHmJpDSu-IvpuKigEN2pzgWtSo--Rwd-n78nrWnZzeDc187Ln3qHlw5LRGrX4qgLQ-y",
"y": "ANIbFeRdPHf1WYMCUjcPz-ZhecZFybOqLIJjVOlLETH7uPlyG0gEoMWnIZXhQVypPy_HtUiUzdnSEPAylYhHBTX2"
}}`,
},
} {
t.Run(tc.name, func(t *testing.T) {
var jwk JsonWebKey2020
err := json.Unmarshal([]byte(tc.str), &jwk)
require.NoError(t, err)
bytes, err := json.Marshal(jwk)
require.NoError(t, err)
require.JSONEq(t, tc.str, string(bytes))
})
}
}

View File

@@ -0,0 +1,120 @@
package jsonwebkey
import (
"encoding/base64"
"encoding/json"
"fmt"
"math/big"
"github.com/INFURA/go-did/crypto"
"github.com/INFURA/go-did/crypto/ed25519"
"github.com/INFURA/go-did/crypto/p256"
"github.com/INFURA/go-did/crypto/x25519"
)
// Specification:
// - https://www.rfc-editor.org/rfc/rfc7517#section-4 (JWK)
// - https://www.iana.org/assignments/jose/jose.xhtml#web-key-types (key parameters)
type jwk struct {
pubkey crypto.PublicKey
}
func (j jwk) MarshalJSON() ([]byte, error) {
switch pubkey := j.pubkey.(type) {
case *p256.PublicKey:
return json.Marshal(struct {
Kty string `json:"kty"`
Crv string `json:"crv"`
X string `json:"x"`
Y string `json:"y"`
}{
Kty: "EC",
Crv: "P-256",
X: base64.RawURLEncoding.EncodeToString(pubkey.X.Bytes()),
Y: base64.RawURLEncoding.EncodeToString(pubkey.Y.Bytes()),
})
case ed25519.PublicKey:
return json.Marshal(struct {
Kty string `json:"kty"`
Crv string `json:"crv"`
X string `json:"x"`
}{
Kty: "OKP",
Crv: "Ed25519",
X: base64.RawURLEncoding.EncodeToString(pubkey.ToBytes()),
})
case *x25519.PublicKey:
return json.Marshal(struct {
Kty string `json:"kty"`
Crv string `json:"crv"`
X string `json:"x"`
}{
Kty: "OKP",
Crv: "X25519",
X: base64.RawURLEncoding.EncodeToString(pubkey.ToBytes()),
})
default:
return nil, fmt.Errorf("unsupported key type %T", pubkey)
}
}
func (j *jwk) UnmarshalJSON(bytes []byte) error {
aux := make(map[string]string)
err := json.Unmarshal(bytes, &aux)
if err != nil {
return err
}
bigIntBase64Url := func(s string) (*big.Int, error) {
raw, err := base64.RawURLEncoding.DecodeString(s)
if err != nil {
return nil, err
}
return new(big.Int).SetBytes(raw), nil
}
switch aux["kty"] {
case "EC": // Elliptic curve
x, err := bigIntBase64Url(aux["x"])
if err != nil {
return fmt.Errorf("invalid x parameter with kty=EC: %w", err)
}
y, err := bigIntBase64Url(aux["y"])
if err != nil {
return fmt.Errorf("invalid y parameter with kty=EC: %w", err)
}
switch aux["crv"] {
case "P-256":
j.pubkey, err = p256.PublicKeyFromXY(x, y)
return err
default:
return fmt.Errorf("unsupported Curve %s", aux["crv"])
}
case "RSA":
return fmt.Errorf("not implemented")
case "OKP": // Octet key pair
x, err := base64.RawURLEncoding.DecodeString(aux["x"])
if err != nil {
return fmt.Errorf("invalid x parameter with kty=OKP: %w", err)
}
switch aux["crv"] {
case "Ed25519":
j.pubkey, err = ed25519.PublicKeyFromBytes(x)
return err
case "X25519":
j.pubkey, err = x25519.PublicKeyFromBytes(x)
return err
default:
return fmt.Errorf("unsupported Curve %s", aux["crv"])
}
default:
return fmt.Errorf("unsupported key type %s", aux["kty"])
}
}

View File

@@ -69,6 +69,10 @@ func (m *MultiKey) UnmarshalJSON(bytes []byte) error {
if len(m.id) == 0 {
return errors.New("invalid id")
}
m.controller = aux.Controller
if !did.HasValidDIDSyntax(m.controller) {
return errors.New("invalid controller")
}
code, pubBytes, err := helpers.PublicKeyMultibaseDecode(aux.PublicKeyMultibase)
if err != nil {
@@ -83,10 +87,6 @@ func (m *MultiKey) UnmarshalJSON(bytes []byte) error {
return fmt.Errorf("invalid publicKeyMultibase: %w", err)
}
m.controller = aux.Controller
if !did.HasValidDIDSyntax(m.controller) {
return errors.New("invalid controller")
}
return nil
}