Skip to content

Commit

Permalink
feat: Ed25519Signature2020 (#35)
Browse files Browse the repository at this point in the history
* feat: add support for 2020

* feat: add test for 2020

* fix: x25519 key
  • Loading branch information
skynet2 authored Nov 20, 2024
1 parent 885af63 commit 0c5631a
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 15 deletions.
30 changes: 24 additions & 6 deletions method/key/creator.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,17 @@ const (
schemaResV1 = "https://w3id.org/did-resolution/v1"
schemaDIDV1 = "https://w3id.org/did/v1"
ed25519VerificationKey2018 = "Ed25519VerificationKey2018"
ed25519VerificationKey2020 = "Ed25519VerificationKey2020"
x25519KeyAgreementKey2019 = "X25519KeyAgreementKey2019"
x25519KeyAgreementKey2020 = "X25519KeyAgreementKey2020"
bls12381G2Key2020 = "Bls12381G2Key2020"
jsonWebKey2020 = "JsonWebKey2020"
)

// Create new DID document for didDoc.
// Either didDoc must contain non-empty VerificationMethod[] or opts must contain KeyType value of kms.KeyType to create
// a new key and a corresponding *VerificationMethod entry.
// nolint:gocyclo
func (v *VDR) Create(didDoc *did.Doc, opts ...vdrapi.DIDMethodOption) (*did.DocResolution, error) {
createDIDOpts := &vdrapi.DIDMethodOpts{Values: make(map[string]interface{})}
// Apply options
Expand All @@ -48,7 +51,9 @@ func (v *VDR) Create(didDoc *did.Doc, opts ...vdrapi.DIDMethodOption) (*did.DocR
return nil, fmt.Errorf("verification method is empty")
}

switch didDoc.VerificationMethod[0].Type {
verificationMethodType := didDoc.VerificationMethod[0].Type

switch verificationMethodType {
case jsonWebKey2020:
didKey, keyID, err = fingerprint.CreateDIDKeyByJwk(didDoc.VerificationMethod[0].JSONWebKey())
if err != nil {
Expand All @@ -66,8 +71,10 @@ func (v *VDR) Create(didDoc *did.Doc, opts ...vdrapi.DIDMethodOption) (*did.DocR
publicKey = did.NewVerificationMethodFromBytes(keyID, didDoc.VerificationMethod[0].Type, didKey,
didDoc.VerificationMethod[0].Value)

if didDoc.VerificationMethod[0].Type == ed25519VerificationKey2018 {
keyAgr, err = keyAgreementFromEd25519(didKey, didDoc.VerificationMethod[0].Value)
if verificationMethodType == ed25519VerificationKey2018 ||
verificationMethodType == ed25519VerificationKey2020 {
keyAgr, err = keyAgreementFromEd25519(didKey, didDoc.VerificationMethod[0].Value,
verificationMethodType)
if err != nil {
return nil, err
}
Expand All @@ -91,7 +98,7 @@ func getKeyCode(verificationMethod *did.VerificationMethod) (uint64, error) {
var keyCode uint64

switch verificationMethod.Type {
case ed25519VerificationKey2018:
case ed25519VerificationKey2018, ed25519VerificationKey2020:
keyCode = fingerprint.ED25519PubKeyMultiCodec
case bls12381G2Key2020:
keyCode = fingerprint.BLS12381g2PubKeyMultiCodec
Expand Down Expand Up @@ -126,15 +133,26 @@ func createDoc(pubKey, keyAgreement *did.VerificationMethod, didKey string) *did
}
}

func keyAgreementFromEd25519(didKey string, ed25519PubKey []byte) (*did.VerificationMethod, error) {
func keyAgreementFromEd25519(
didKey string,
ed25519PubKey []byte,
verificationMethodType string,
) (*did.VerificationMethod, error) {
curve25519PubKey, err := cryptoutil.PublicEd25519toCurve25519(ed25519PubKey)
if err != nil {
return nil, err
}

agreement := x25519KeyAgreementKey2019

if verificationMethodType == ed25519VerificationKey2020 {
agreement = x25519KeyAgreementKey2020
}

fp := fingerprint.KeyFingerprint(fingerprint.X25519PubKeyMultiCodec, curve25519PubKey)
keyID := fmt.Sprintf("%s#%s", didKey, fp)
pubKey := did.NewVerificationMethodFromBytes(keyID, x25519KeyAgreementKey2019, didKey, curve25519PubKey)

pubKey := did.NewVerificationMethodFromBytes(keyID, agreement, didKey, curve25519PubKey)

return pubKey, nil
}
28 changes: 24 additions & 4 deletions method/key/creator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,22 @@ func TestBuild(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, docResolution.DIDDocument)

assertEd25519Doc(t, docResolution.DIDDocument)
assertEd25519Doc(t, docResolution.DIDDocument, pubKey.Type, x25519KeyAgreementKey2019)
})

t.Run("build with default key type", func(t *testing.T) {
v := New()

pubKey := did.VerificationMethod{
Type: ed25519VerificationKey2020,
Value: base58.Decode(pubKeyBase58Ed25519),
}

docResolution, err := v.Create(&did.Doc{VerificationMethod: []did.VerificationMethod{pubKey}})
require.NoError(t, err)
require.NotNil(t, docResolution.DIDDocument)

assertEd25519Doc(t, docResolution.DIDDocument, pubKey.Type, x25519KeyAgreementKey2020)
})

t.Run("build with BLS12381G2 key type", func(t *testing.T) {
Expand Down Expand Up @@ -190,7 +205,12 @@ func TestBuild(t *testing.T) {
})
}

func assertEd25519Doc(t *testing.T, doc *did.Doc) {
func assertEd25519Doc(
t *testing.T,
doc *did.Doc,
expectedVerificationKeyType string,
agreement string,
) {
const (
didKey = "did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH"
didKeyID = "did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH#z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH" //nolint:lll
Expand All @@ -200,8 +220,8 @@ func assertEd25519Doc(t *testing.T, doc *did.Doc) {
keyAgreementBase58 = "JhNWeSVLMYccCk7iopQW4guaSJTojqpMEELgSLhKwRr"
)

assertDualBase58Doc(t, doc, didKey, didKeyID, ed25519VerificationKey2018, pubKeyBase58,
agreementKeyID, x25519KeyAgreementKey2019, keyAgreementBase58)
assertDualBase58Doc(t, doc, didKey, didKeyID, expectedVerificationKeyType, pubKeyBase58,
agreementKeyID, agreement, keyAgreementBase58)
}

func assertBBSDoc(t *testing.T, doc *did.Doc) {
Expand Down
8 changes: 4 additions & 4 deletions method/key/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func (v *VDR) Read(didKey string, _ ...vdrapi.DIDMethodOption) (*did.DocResoluti
func createDIDDocFromPubKey(kid string, code uint64, pubKeyBytes []byte) (*did.Doc, error) {
switch code {
case fingerprint.ED25519PubKeyMultiCodec:
return createEd25519DIDDoc(kid, pubKeyBytes)
return createEd25519DIDDoc(kid, pubKeyBytes, ed25519VerificationKey2018)
case fingerprint.BLS12381g2PubKeyMultiCodec, fingerprint.BLS12381g1g2PubKeyMultiCodec:
return createBase58DIDDoc(kid, bls12381G2Key2020, pubKeyBytes)
case fingerprint.P256PubKeyMultiCodec, fingerprint.P384PubKeyMultiCodec, fingerprint.P521PubKeyMultiCodec:
Expand Down Expand Up @@ -115,20 +115,20 @@ func createJSONWebKey2020DIDDoc(kid string, code uint64, pubKeyBytes []byte) (*d
return didDoc, nil
}

func createEd25519DIDDoc(kid string, pubKeyBytes []byte) (*did.Doc, error) {
func createEd25519DIDDoc(kid string, pubKeyBytes []byte, verificationKeyType string) (*did.Doc, error) {
didKey := fmt.Sprintf("did:key:%s", kid)

// did:key can't add non converted encryption key as keyAgreement (unless it's added as an option just like creator,
// it can be added and read here if needed. Below TODO is a reminder for this)
// TODO find a way to get the Encryption key as in creator.go
// for now keeping original ed25519 to X25519 key conversion as keyAgreement.
keyAgr, err := keyAgreementFromEd25519(didKey, pubKeyBytes)
keyAgr, err := keyAgreementFromEd25519(didKey, pubKeyBytes, verificationKeyType)
if err != nil {
return nil, fmt.Errorf("pub:key vdr Read: failed to fetch KeyAgreement: %w", err)
}

keyID := fmt.Sprintf("%s#%s", didKey, kid)
publicKey := did.NewVerificationMethodFromBytes(keyID, ed25519VerificationKey2018, didKey, pubKeyBytes)
publicKey := did.NewVerificationMethodFromBytes(keyID, verificationKeyType, didKey, pubKeyBytes)

didDoc := createDoc(publicKey, keyAgr, didKey)

Expand Down
2 changes: 1 addition & 1 deletion method/key/resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func TestReadEd25519(t *testing.T) {
require.NotNil(t, docResolution.DIDDocument)
require.True(t, docResolution.DIDDocument.KeyAgreement[0].Embedded)

assertEd25519Doc(t, docResolution.DIDDocument)
assertEd25519Doc(t, docResolution.DIDDocument, ed25519VerificationKey2018, x25519KeyAgreementKey2019)
})
}

Expand Down

0 comments on commit 0c5631a

Please sign in to comment.