did🔑 green test with the test vectors
This commit is contained in:
@@ -9,15 +9,19 @@ import (
|
||||
"github.com/INFURA/go-did/crypto/p256"
|
||||
"github.com/INFURA/go-did/crypto/p384"
|
||||
"github.com/INFURA/go-did/crypto/p521"
|
||||
"github.com/INFURA/go-did/crypto/rsa"
|
||||
"github.com/INFURA/go-did/crypto/secp256k1"
|
||||
"github.com/INFURA/go-did/crypto/x25519"
|
||||
)
|
||||
|
||||
var decoders = map[uint64]func(b []byte) (crypto.PublicKey, error){
|
||||
ed25519.MultibaseCode: func(b []byte) (crypto.PublicKey, error) { return ed25519.PublicKeyFromBytes(b) },
|
||||
p256.MultibaseCode: func(b []byte) (crypto.PublicKey, error) { return p256.PublicKeyFromBytes(b) },
|
||||
p384.MultibaseCode: func(b []byte) (crypto.PublicKey, error) { return p384.PublicKeyFromBytes(b) },
|
||||
p521.MultibaseCode: func(b []byte) (crypto.PublicKey, error) { return p521.PublicKeyFromBytes(b) },
|
||||
x25519.MultibaseCode: func(b []byte) (crypto.PublicKey, error) { return x25519.PublicKeyFromBytes(b) },
|
||||
ed25519.MultibaseCode: func(b []byte) (crypto.PublicKey, error) { return ed25519.PublicKeyFromBytes(b) },
|
||||
p256.MultibaseCode: func(b []byte) (crypto.PublicKey, error) { return p256.PublicKeyFromBytes(b) },
|
||||
p384.MultibaseCode: func(b []byte) (crypto.PublicKey, error) { return p384.PublicKeyFromBytes(b) },
|
||||
p521.MultibaseCode: func(b []byte) (crypto.PublicKey, error) { return p521.PublicKeyFromBytes(b) },
|
||||
rsa.MultibaseCode: func(b []byte) (crypto.PublicKey, error) { return rsa.PublicKeyFromPKCS1DER(b) },
|
||||
secp256k1.MultibaseCode: func(b []byte) (crypto.PublicKey, error) { return secp256k1.PublicKeyFromBytes(b) },
|
||||
x25519.MultibaseCode: func(b []byte) (crypto.PublicKey, error) { return x25519.PublicKeyFromBytes(b) },
|
||||
}
|
||||
|
||||
// PublicKeyFromPublicKeyMultibase decodes the public key from its PublicKeyMultibase form
|
||||
|
||||
@@ -29,6 +29,9 @@ type TestHarness[PubT crypto.PublicKey, PrivT crypto.PrivateKey] struct {
|
||||
|
||||
MultibaseCode uint64
|
||||
|
||||
DefaultHash crypto.Hash
|
||||
OtherHashes []crypto.Hash
|
||||
|
||||
PublicKeyBytesSize int
|
||||
PrivateKeyBytesSize int
|
||||
SignatureBytesSize int
|
||||
@@ -198,10 +201,12 @@ func TestSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](t *testing.T, har
|
||||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
signer func(msg []byte) ([]byte, error)
|
||||
verifier func(msg []byte, sig []byte) bool
|
||||
signer func(msg []byte, opts ...crypto.SigningOption) ([]byte, error)
|
||||
verifier func(msg []byte, sig []byte, opts ...crypto.SigningOption) bool
|
||||
expectedSize int
|
||||
stats *int
|
||||
defaultHash crypto.Hash
|
||||
otherHashes []crypto.Hash
|
||||
}{
|
||||
{
|
||||
name: "Bytes signature",
|
||||
@@ -209,32 +214,59 @@ func TestSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](t *testing.T, har
|
||||
verifier: spub.VerifyBytes,
|
||||
expectedSize: harness.SignatureBytesSize,
|
||||
stats: &stats.sigRawSize,
|
||||
defaultHash: harness.DefaultHash,
|
||||
otherHashes: harness.OtherHashes,
|
||||
},
|
||||
{
|
||||
name: "ASN.1 signature",
|
||||
signer: spriv.SignToASN1,
|
||||
verifier: spub.VerifyASN1,
|
||||
stats: &stats.sigAsn1Size,
|
||||
name: "ASN.1 signature",
|
||||
signer: spriv.SignToASN1,
|
||||
verifier: spub.VerifyASN1,
|
||||
stats: &stats.sigAsn1Size,
|
||||
defaultHash: harness.DefaultHash,
|
||||
otherHashes: harness.OtherHashes,
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
msg := []byte("message")
|
||||
|
||||
sig, err := tc.signer(msg)
|
||||
sigNoParams, err := tc.signer(msg)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, sigNoParams)
|
||||
|
||||
sigDefault, err := tc.signer(msg, crypto.WithSigningHash(tc.defaultHash))
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, sig)
|
||||
|
||||
if tc.expectedSize > 0 {
|
||||
require.Equal(t, tc.expectedSize, len(sig))
|
||||
require.Equal(t, tc.expectedSize, len(sigNoParams))
|
||||
}
|
||||
*tc.stats = len(sig)
|
||||
*tc.stats = len(sigNoParams)
|
||||
|
||||
valid := tc.verifier(msg, sig)
|
||||
// signatures might be different (i.e. non-deterministic), but they should verify the same way
|
||||
valid := tc.verifier(msg, sigNoParams)
|
||||
require.True(t, valid)
|
||||
valid = tc.verifier(msg, sigDefault)
|
||||
require.True(t, valid)
|
||||
|
||||
valid = tc.verifier([]byte("wrong message"), sig)
|
||||
valid = tc.verifier([]byte("wrong message"), sigNoParams)
|
||||
require.False(t, valid)
|
||||
valid = tc.verifier([]byte("wrong message"), sigDefault)
|
||||
require.False(t, valid)
|
||||
})
|
||||
for _, hash := range tc.otherHashes {
|
||||
t.Run(fmt.Sprintf("%s-%s", tc.name, hash.String()), func(t *testing.T) {
|
||||
msg := []byte("message")
|
||||
|
||||
sig, err := tc.signer(msg)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, sig)
|
||||
|
||||
valid := tc.verifier(msg, sig)
|
||||
require.True(t, valid)
|
||||
|
||||
valid = tc.verifier([]byte("wrong message"), sig)
|
||||
require.False(t, valid)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -20,6 +20,11 @@ func (d document) MarshalJSON() ([]byte, error) {
|
||||
// Maybe it doesn't matter, but the spec contradicts itself.
|
||||
// See https://github.com/w3c-ccg/did-key-spec/issues/71
|
||||
|
||||
vms := []did.VerificationMethod{d.signature}
|
||||
if d.signature != did.VerificationMethod(d.keyAgreement) {
|
||||
vms = append(vms, d.keyAgreement)
|
||||
}
|
||||
|
||||
return json.Marshal(struct {
|
||||
Context []string `json:"@context"`
|
||||
ID string `json:"id"`
|
||||
@@ -28,17 +33,17 @@ func (d document) MarshalJSON() ([]byte, error) {
|
||||
VerificationMethod []did.VerificationMethod `json:"verificationMethod,omitempty"`
|
||||
Authentication []string `json:"authentication,omitempty"`
|
||||
AssertionMethod []string `json:"assertionMethod,omitempty"`
|
||||
KeyAgreement []did.VerificationMethod `json:"keyAgreement,omitempty"`
|
||||
KeyAgreement []string `json:"keyAgreement,omitempty"`
|
||||
CapabilityInvocation []string `json:"capabilityInvocation,omitempty"`
|
||||
CapabilityDelegation []string `json:"capabilityDelegation,omitempty"`
|
||||
}{
|
||||
Context: d.Context(),
|
||||
ID: d.id.String(),
|
||||
AlsoKnownAs: nil,
|
||||
VerificationMethod: []did.VerificationMethod{d.signature},
|
||||
VerificationMethod: vms,
|
||||
Authentication: []string{d.signature.ID()},
|
||||
AssertionMethod: []string{d.signature.ID()},
|
||||
KeyAgreement: []did.VerificationMethod{d.keyAgreement},
|
||||
KeyAgreement: []string{d.keyAgreement.ID()},
|
||||
CapabilityInvocation: []string{d.signature.ID()},
|
||||
CapabilityDelegation: []string{d.signature.ID()},
|
||||
})
|
||||
@@ -66,6 +71,11 @@ func (d document) AlsoKnownAs() []*url.URL {
|
||||
}
|
||||
|
||||
func (d document) VerificationMethods() map[string]did.VerificationMethod {
|
||||
if d.signature == did.VerificationMethod(d.keyAgreement) {
|
||||
return map[string]did.VerificationMethod{
|
||||
d.signature.ID(): d.signature,
|
||||
}
|
||||
}
|
||||
return map[string]did.VerificationMethod{
|
||||
d.signature.ID(): d.signature,
|
||||
d.keyAgreement.ID(): d.keyAgreement,
|
||||
|
||||
@@ -7,20 +7,19 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/INFURA/go-did"
|
||||
"github.com/INFURA/go-did/methods/did-key/testvectors"
|
||||
)
|
||||
|
||||
func TestDocument(t *testing.T) {
|
||||
d, err := did.Parse("did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK")
|
||||
require.NoError(t, err)
|
||||
|
||||
doc, err := d.Document()
|
||||
doc, err := d.Document(did.WithResolutionHintVerificationMethod("Ed25519VerificationKey2020"))
|
||||
require.NoError(t, err)
|
||||
|
||||
bytes, err := json.MarshalIndent(doc, "", " ")
|
||||
require.NoError(t, err)
|
||||
|
||||
// TODO: https://github.com/w3c-ccg/did-key-spec/issues/71
|
||||
|
||||
const expected = `{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/did/v1",
|
||||
@@ -54,8 +53,113 @@ func TestDocument(t *testing.T) {
|
||||
}]
|
||||
}`
|
||||
|
||||
require.JSONEq(t, expected, string(bytes))
|
||||
requireDocEqual(t, expected, string(bytes))
|
||||
}
|
||||
|
||||
// TODO: test vectors:
|
||||
// https://github.com/w3c-ccg/did-key-spec/tree/main/test-vectors
|
||||
func TestVectors(t *testing.T) {
|
||||
for _, filename := range testvectors.AllFiles() {
|
||||
t.Run(filename, func(t *testing.T) {
|
||||
vectors, err := testvectors.LoadTestVectors(filename)
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, vector := range vectors {
|
||||
t.Run(vector.DID, func(t *testing.T) {
|
||||
t.Log("hint is", vector.ResolutionHint)
|
||||
require.NotZero(t, vector.Document)
|
||||
require.NotZero(t, vector.Pub)
|
||||
require.NotZero(t, vector.Priv)
|
||||
|
||||
d, err := did.Parse(vector.DID)
|
||||
require.NoError(t, err)
|
||||
|
||||
var opts []did.ResolutionOption
|
||||
for _, hint := range vector.ResolutionHint {
|
||||
opts = append(opts, did.WithResolutionHintVerificationMethod(hint))
|
||||
}
|
||||
|
||||
doc, err := d.Document(opts...)
|
||||
require.NoError(t, err)
|
||||
bytes, err := json.MarshalIndent(doc, "", " ")
|
||||
require.NoError(t, err)
|
||||
requireDocEqual(t, vector.Document, string(bytes))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Some variations in the DID document are legal, so we can't just require.JSONEq() to compare two of them.
|
||||
// This function does its best to compare two documents, regardless of those variations.
|
||||
func requireDocEqual(t *testing.T, expected, actual string) {
|
||||
propsExpected := map[string]json.RawMessage{}
|
||||
err := json.Unmarshal([]byte(expected), &propsExpected)
|
||||
require.NoError(t, err)
|
||||
|
||||
propsActual := map[string]json.RawMessage{}
|
||||
err = json.Unmarshal([]byte(actual), &propsActual)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, len(propsExpected), len(propsActual))
|
||||
|
||||
// if a VerificationMethod is defined inline in the properties below, we move it to vmExpected and replace it with the VM ID
|
||||
var vmExpected []json.RawMessage
|
||||
err = json.Unmarshal(propsExpected["verificationMethod"], &vmExpected)
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, s := range []string{"authentication", "assertionMethod", "keyAgreement", "capabilityInvocation", "capabilityDelegation"} {
|
||||
var vms []json.RawMessage
|
||||
err = json.Unmarshal(propsExpected[s], &vms)
|
||||
require.NoError(t, err)
|
||||
for _, vmBytes := range vms {
|
||||
vm := map[string]json.RawMessage{}
|
||||
if err := json.Unmarshal(vmBytes, &vm); err == nil {
|
||||
vmExpected = append(vmExpected, vmBytes)
|
||||
propsExpected[s] = append([]byte("[ "), append(vm["id"], []byte(" ]")...)...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Same for actual
|
||||
var vmActual []json.RawMessage
|
||||
err = json.Unmarshal(propsActual["verificationMethod"], &vmActual)
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, s := range []string{"authentication", "assertionMethod", "keyAgreement", "capabilityInvocation", "capabilityDelegation"} {
|
||||
var vms []json.RawMessage
|
||||
err = json.Unmarshal(propsActual[s], &vms)
|
||||
require.NoError(t, err)
|
||||
for _, vmBytes := range vms {
|
||||
vm := map[string]json.RawMessage{}
|
||||
if err := json.Unmarshal(vmBytes, &vm); err == nil {
|
||||
vmActual = append(vmActual, vmBytes)
|
||||
propsActual[s] = append([]byte("[ "), append(vm["id"], []byte(" ]")...)...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range propsExpected {
|
||||
switch k {
|
||||
case "verificationMethod":
|
||||
// Convert to interface{} slices to normalize JSON formatting
|
||||
expectedVMs := make([]interface{}, len(vmExpected))
|
||||
for i, vm := range vmExpected {
|
||||
var normalized interface{}
|
||||
err := json.Unmarshal(vm, &normalized)
|
||||
require.NoError(t, err)
|
||||
expectedVMs[i] = normalized
|
||||
}
|
||||
|
||||
actualVMs := make([]interface{}, len(vmActual))
|
||||
for i, vm := range vmActual {
|
||||
var normalized interface{}
|
||||
err := json.Unmarshal(vm, &normalized)
|
||||
require.NoError(t, err)
|
||||
actualVMs[i] = normalized
|
||||
}
|
||||
|
||||
require.ElementsMatch(t, expectedVMs, actualVMs, "--> on property \"%s\"", k)
|
||||
default:
|
||||
require.JSONEq(t, string(v), string(propsActual[k]), "--> on property \"%s\"", k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,9 +11,14 @@ import (
|
||||
"github.com/INFURA/go-did/crypto/p256"
|
||||
"github.com/INFURA/go-did/crypto/p384"
|
||||
"github.com/INFURA/go-did/crypto/p521"
|
||||
"github.com/INFURA/go-did/crypto/rsa"
|
||||
"github.com/INFURA/go-did/crypto/secp256k1"
|
||||
"github.com/INFURA/go-did/crypto/x25519"
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -23,12 +28,11 @@ func init() {
|
||||
did.RegisterMethod("key", Decode)
|
||||
}
|
||||
|
||||
var _ did.DID = &DidKey{}
|
||||
var _ did.DID = DidKey{}
|
||||
|
||||
type DidKey struct {
|
||||
msi string // method-specific identifier, i.e. "12345" in "did:key:12345"
|
||||
signature did.VerificationMethodSignature
|
||||
keyAgreement did.VerificationMethodKeyAgreement
|
||||
msi string // method-specific identifier, i.e. "12345" in "did:key:12345"
|
||||
pubkey crypto.PublicKey
|
||||
}
|
||||
|
||||
func Decode(identifier string) (did.DID, error) {
|
||||
@@ -44,38 +48,14 @@ func Decode(identifier string) (did.DID, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %w", did.ErrInvalidDid, err)
|
||||
}
|
||||
d, err := FromPublicKey(pub)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %w", did.ErrInvalidDid, err)
|
||||
}
|
||||
return d, nil
|
||||
return DidKey{msi: msi, pubkey: pub}, nil
|
||||
}
|
||||
|
||||
func FromPublicKey(pub crypto.PublicKey) (did.DID, error) {
|
||||
switch pub := pub.(type) {
|
||||
case ed25519.PublicKey:
|
||||
d := DidKey{msi: pub.ToPublicKeyMultibase()}
|
||||
d.signature = ed25519vm.NewVerificationKey2020(fmt.Sprintf("did:key:%s#%s", d.msi, d.msi), pub, d)
|
||||
xpub, err := x25519.PublicKeyFromEd25519(pub)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
xmsi := xpub.ToPublicKeyMultibase()
|
||||
d.keyAgreement = x25519vm.NewKeyAgreementKey2020(fmt.Sprintf("did:key:%s#%s", d.msi, xmsi), xpub, d)
|
||||
return d, nil
|
||||
case *p256.PublicKey, *p384.PublicKey, *p521.PublicKey:
|
||||
d := DidKey{msi: pub.ToPublicKeyMultibase()}
|
||||
mk := multikey.NewMultiKey(fmt.Sprintf("did:key:%s#%s", d.msi, d.msi), pub, d)
|
||||
d.signature = mk
|
||||
d.keyAgreement = mk
|
||||
return d, nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported public key: %T", pub)
|
||||
}
|
||||
func FromPublicKey(pub crypto.PublicKey) did.DID {
|
||||
return DidKey{msi: pub.ToPublicKeyMultibase()}
|
||||
}
|
||||
|
||||
func FromPrivateKey(priv crypto.PrivateKey) (did.DID, error) {
|
||||
func FromPrivateKey(priv crypto.PrivateKey) did.DID {
|
||||
return FromPublicKey(priv.Public().(crypto.PublicKey))
|
||||
}
|
||||
|
||||
@@ -83,12 +63,92 @@ func (d DidKey) Method() string {
|
||||
return "key"
|
||||
}
|
||||
|
||||
func (d DidKey) Document() (did.Document, error) {
|
||||
return document{
|
||||
id: d,
|
||||
signature: d.signature,
|
||||
keyAgreement: d.keyAgreement,
|
||||
}, nil
|
||||
func (d DidKey) Document(opts ...did.ResolutionOption) (did.Document, error) {
|
||||
params := did.CollectResolutionOpts(opts)
|
||||
|
||||
doc := document{id: d}
|
||||
mainVmId := fmt.Sprintf("did:key:%s#%s", d.msi, d.msi)
|
||||
|
||||
switch pub := d.pubkey.(type) {
|
||||
case ed25519.PublicKey:
|
||||
xpub, err := x25519.PublicKeyFromEd25519(pub)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
xmsi := xpub.ToPublicKeyMultibase()
|
||||
xVmId := fmt.Sprintf("did:key:%s#%s", d.msi, xmsi)
|
||||
|
||||
switch {
|
||||
case params.HasVerificationMethodHint(jsonwebkey.Type):
|
||||
doc.signature = jsonwebkey.NewJsonWebKey2020(mainVmId, pub, d)
|
||||
doc.keyAgreement = jsonwebkey.NewJsonWebKey2020(xVmId, xpub, d)
|
||||
case params.HasVerificationMethodHint(multikey.Type):
|
||||
doc.signature = multikey.NewMultiKey(mainVmId, pub, d)
|
||||
doc.keyAgreement = multikey.NewMultiKey(xVmId, xpub, d)
|
||||
default:
|
||||
if params.HasVerificationMethodHint(ed25519vm.Type2018) {
|
||||
doc.signature = ed25519vm.NewVerificationKey2018(mainVmId, pub, d)
|
||||
}
|
||||
if params.HasVerificationMethodHint(x25519vm.Type2019) {
|
||||
doc.keyAgreement = x25519vm.NewKeyAgreementKey2019(xVmId, xpub, d)
|
||||
}
|
||||
if doc.signature == nil {
|
||||
doc.signature = ed25519vm.NewVerificationKey2020(mainVmId, pub, d)
|
||||
}
|
||||
if doc.keyAgreement == nil {
|
||||
doc.keyAgreement = x25519vm.NewKeyAgreementKey2020(xVmId, xpub, d)
|
||||
}
|
||||
}
|
||||
|
||||
case *p256.PublicKey:
|
||||
switch {
|
||||
case params.HasVerificationMethodHint(jsonwebkey.Type):
|
||||
jwk := jsonwebkey.NewJsonWebKey2020(mainVmId, pub, d)
|
||||
doc.signature = jwk
|
||||
doc.keyAgreement = jwk
|
||||
case params.HasVerificationMethodHint(p256vm.Type2021):
|
||||
vm := p256vm.NewKey2021(mainVmId, pub, d)
|
||||
doc.signature = vm
|
||||
doc.keyAgreement = vm
|
||||
default:
|
||||
mk := multikey.NewMultiKey(mainVmId, pub, d)
|
||||
doc.signature = mk
|
||||
doc.keyAgreement = mk
|
||||
}
|
||||
|
||||
case *secp256k1.PublicKey:
|
||||
switch {
|
||||
case params.HasVerificationMethodHint(jsonwebkey.Type):
|
||||
jwk := jsonwebkey.NewJsonWebKey2020(mainVmId, pub, d)
|
||||
doc.signature = jwk
|
||||
doc.keyAgreement = jwk
|
||||
case params.HasVerificationMethodHint(secp256k1vm.Type):
|
||||
vm := secp256k1vm.NewVerificationKey2019(mainVmId, pub, d)
|
||||
doc.signature = vm
|
||||
doc.keyAgreement = vm
|
||||
default:
|
||||
mk := multikey.NewMultiKey(mainVmId, pub, d)
|
||||
doc.signature = mk
|
||||
doc.keyAgreement = mk
|
||||
}
|
||||
|
||||
case *p384.PublicKey, *p521.PublicKey, *rsa.PublicKey:
|
||||
switch {
|
||||
case params.HasVerificationMethodHint(jsonwebkey.Type):
|
||||
jwk := jsonwebkey.NewJsonWebKey2020(mainVmId, pub, d)
|
||||
doc.signature = jwk
|
||||
doc.keyAgreement = jwk
|
||||
default:
|
||||
mk := multikey.NewMultiKey(mainVmId, pub, d)
|
||||
doc.signature = mk
|
||||
doc.keyAgreement = mk
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported public key: %T", pub)
|
||||
}
|
||||
|
||||
return doc, nil
|
||||
}
|
||||
|
||||
func (d DidKey) String() string {
|
||||
@@ -103,5 +163,8 @@ func (d DidKey) Equal(d2 did.DID) bool {
|
||||
if d2, ok := d2.(DidKey); ok {
|
||||
return d.msi == d2.msi
|
||||
}
|
||||
if d2, ok := d2.(*DidKey); ok {
|
||||
return d.msi == d2.msi
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -20,8 +20,7 @@ func ExampleGenerateKeyPair() {
|
||||
fmt.Println("Private key:", base64.StdEncoding.EncodeToString(priv.ToBytes()))
|
||||
|
||||
// Make the associated did:key
|
||||
dk, err := didkey.FromPrivateKey(priv)
|
||||
handleErr(err)
|
||||
dk := didkey.FromPrivateKey(priv)
|
||||
fmt.Println("Did:", dk.String())
|
||||
|
||||
// Produce a signature
|
||||
|
||||
Reference in New Issue
Block a user