dev guidelines, some cleanup
This commit is contained in:
36
design.md
Normal file
36
design.md
Normal file
@@ -0,0 +1,36 @@
|
||||
## Development guidelines
|
||||
|
||||
See [Readme.md](Readme.md) as well.
|
||||
|
||||
General:
|
||||
- coding style should be clean, straightforward and documented, in a similar fashion as go-ucan.
|
||||
- keep the dependencies minimal, favor the standard go libraries
|
||||
- code should be decently tested and profiled
|
||||
- specifications and test vectors used MUST be referenced in a comment
|
||||
- if something differs from a specification, it should be documented and explained
|
||||
- generally, follow the existing structure of did:key, ed25519 or x25519
|
||||
- consider how an average user will read and understand your code, rather than how you read it
|
||||
|
||||
DIDs:
|
||||
- DID and document structs are minimal/lightweight and get expanded into the relevant interface (DID, Document).
|
||||
- They get flattened when marshalling into JSON but not otherwise. DID Documents are for out-of-process communication, not the normal path.
|
||||
- this library should also have a generic Document struct, to accept arbitrary DID documents in JSON format
|
||||
|
||||
Crypto:
|
||||
- each type of crypto handling should be self-contained in the relevant verification method package (e.g. everything ed25519 is in /verifications/ed25519). This includes the JSON (un)marshalling of the VerificationMethod.
|
||||
- a user of the library shouldn't have to know or care about the underlying crypto to use it "server side" (signature verification, key agreement). Thus, it should be abstracted behind the VerificationMethod interfaces.
|
||||
- for the same reason, each of those packages should expose or alias the relevant types (ex: PublicKey/PrivateKey in /verifications/ed25519) to expose a regular way to work with crypto primitives, as well as allowing behind the scene upgrades.
|
||||
- for each, we should expose some generally useful functions to handle private keys (generation, marshalling...)
|
||||
|
||||
## Minimal target features
|
||||
|
||||
Methods:
|
||||
- did:key
|
||||
- did:pkh
|
||||
|
||||
Verification Methods:
|
||||
- ed25519
|
||||
- x25519
|
||||
- secp256k1
|
||||
- p256
|
||||
- p384
|
||||
@@ -5,9 +5,11 @@ import (
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// DID is a decoded (i.e. from a string) Decentralized Identifiers.
|
||||
// DID is a decoded (i.e. from a string) Decentralized Identifier.
|
||||
type DID interface {
|
||||
Method() string
|
||||
|
||||
// TODO: below might be only for DID URLs, is it relevant here?
|
||||
Path() string
|
||||
Query() url.Values
|
||||
Fragment() string
|
||||
@@ -15,6 +17,11 @@ type DID interface {
|
||||
Document() (Document, error)
|
||||
String() string // return the full DID URL, with path, query, fragment
|
||||
|
||||
// ResolutionIsExpensive returns true if resolving to a Document is an expensive operation, e.g. requiring
|
||||
// an external HTTP request. By contrast, a self-contained DID (e.g. did:key) can be resolved cheaply without
|
||||
// an external call. This can be an indication whether to cache the resolved state.
|
||||
ResolutionIsExpensive() bool
|
||||
|
||||
Equal(DID) bool
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ func (d document) MarshalJSON() ([]byte, error) {
|
||||
),
|
||||
ID: d.id.String(),
|
||||
AlsoKnownAs: nil,
|
||||
Controller: d.id.String(),
|
||||
VerificationMethod: []did.VerificationMethod{d.signature, d.keyAgreement},
|
||||
Authentication: []string{d.signature.ID()},
|
||||
AssertionMethod: []string{d.signature.ID()},
|
||||
@@ -50,8 +49,8 @@ func (d document) ID() did.DID {
|
||||
}
|
||||
|
||||
func (d document) Controllers() []did.DID {
|
||||
// no external controller possible for did:key
|
||||
return []did.DID{d.id}
|
||||
// no controller for did:key, no changes are possible
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d document) AlsoKnownAs() []url.URL {
|
||||
@@ -23,6 +23,8 @@ func TestDocument(t *testing.T) {
|
||||
|
||||
fmt.Println(string(bytes))
|
||||
|
||||
// TODO: https://github.com/w3c-ccg/did-key-spec/issues/71
|
||||
|
||||
const expected = `{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/did/v1",
|
||||
@@ -23,7 +23,7 @@ func init() {
|
||||
var _ did.DID = &DidKey{}
|
||||
|
||||
type DidKey struct {
|
||||
identifier string // cached value
|
||||
msi string // method-specific identifier, i.e. "12345" in "did:key:12345"
|
||||
signature did.VerificationMethodSignature
|
||||
keyAgreement did.VerificationMethodKeyAgreement
|
||||
}
|
||||
@@ -35,7 +35,9 @@ func Decode(identifier string) (did.DID, error) {
|
||||
return nil, fmt.Errorf("must start with 'did:key'")
|
||||
}
|
||||
|
||||
baseCodec, bytes, err := mbase.Decode(identifier[len(keyPrefix):])
|
||||
msi := identifier[len(keyPrefix):]
|
||||
|
||||
baseCodec, bytes, err := mbase.Decode(msi)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %w", did.ErrInvalidDid, err)
|
||||
}
|
||||
@@ -48,11 +50,11 @@ func Decode(identifier string) (did.DID, error) {
|
||||
return nil, fmt.Errorf("%w: %w", did.ErrInvalidDid, err)
|
||||
}
|
||||
|
||||
d := DidKey{identifier: identifier}
|
||||
d := DidKey{msi: msi}
|
||||
|
||||
switch code {
|
||||
case ed25519.MultibaseCode:
|
||||
d.signature, err = ed25519.NewVerificationKey2020(d.identifier, bytes[read:], d)
|
||||
d.signature, err = ed25519.NewVerificationKey2020(fmt.Sprintf("did:key:%s#%s", msi, msi), bytes[read:], d)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %w", did.ErrInvalidDid, err)
|
||||
}
|
||||
@@ -60,7 +62,7 @@ func Decode(identifier string) (did.DID, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %w", did.ErrInvalidDid, err)
|
||||
}
|
||||
d.keyAgreement, err = x25519.NewKeyAgreementKey2020(d.identifier, xpub, d)
|
||||
d.keyAgreement, err = x25519.NewKeyAgreementKey2020("TODO", xpub, d)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %w", did.ErrInvalidDid, err)
|
||||
}
|
||||
@@ -80,9 +82,9 @@ func FromPublicKey(pub PublicKey) (did.DID, error) {
|
||||
switch pub := pub.(type) {
|
||||
case ed25519.PublicKey:
|
||||
d := DidKey{
|
||||
identifier: ed25519.PublicKeyToMultibase(pub),
|
||||
msi: ed25519.PublicKeyToMultibase(pub),
|
||||
}
|
||||
d.signature, err = ed25519.NewVerificationKey2020(d.identifier, pub, d)
|
||||
d.signature, err = ed25519.NewVerificationKey2020(fmt.Sprintf("did:key:%s#%s", d.msi, d.msi), pub, d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -122,18 +124,26 @@ func (d DidKey) Document() (did.Document, error) {
|
||||
}
|
||||
|
||||
func (d DidKey) String() string {
|
||||
return d.identifier
|
||||
return fmt.Sprintf("did:key:%s", d.msi)
|
||||
}
|
||||
|
||||
func (d DidKey) ResolutionIsExpensive() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (d DidKey) Equal(d2 did.DID) bool {
|
||||
if d2, ok := d2.(DidKey); ok {
|
||||
return d.identifier == d2.identifier
|
||||
return d.msi == d2.msi
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ---------------
|
||||
|
||||
// Below are the interfaces for crypto.PublicKey and crypto.PrivateKey in the go standard library.
|
||||
// They are not actually defined there for compatibility reasons.
|
||||
// They are useful for did:key, it's unclear if it's useful elsewhere.
|
||||
|
||||
type PublicKey interface {
|
||||
Equal(x crypto.PublicKey) bool
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
package didkey_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
mbase "github.com/multiformats/go-multibase"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/INFURA/go-did"
|
||||
_ "github.com/INFURA/go-did/did-key"
|
||||
_ "github.com/INFURA/go-did/methods/did-key"
|
||||
)
|
||||
|
||||
func TestParseDIDKey(t *testing.T) {
|
||||
@@ -41,13 +39,3 @@ func TestEquivalence(t *testing.T) {
|
||||
require.True(t, did0A.Equal(did0B))
|
||||
require.False(t, did0A.Equal(did1))
|
||||
}
|
||||
|
||||
func TestFoo(t *testing.T) {
|
||||
_, bytes, err := mbase.Decode("z6LSj72tK8brWgZja8NLRwPigth2T9QRiG1uH9oKZuKjdh9p")
|
||||
require.NoError(t, err)
|
||||
fmt.Println(bytes)
|
||||
|
||||
_, bytes, err = mbase.Decode("z6LSinnAscp9HxuNE9QCpqiwmSMP7oHiTzLepseUb4y6LHFB")
|
||||
require.NoError(t, err)
|
||||
fmt.Println(bytes)
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
_ "github.com/INFURA/go-did/did-key"
|
||||
_ "github.com/INFURA/go-did/methods/did-key"
|
||||
"github.com/INFURA/go-did/verifications/ed25519"
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user