Add 'did/' from commit 'bd9f680456fff2515614e9d7ed11e5423478b8d5'
git-subtree-dir: did git-subtree-mainline:10d6c3d45dgit-subtree-split:bd9f680456
This commit is contained in:
86
did/did.go
Normal file
86
did/did.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package did
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
mbase "github.com/multiformats/go-multibase"
|
||||
varint "github.com/multiformats/go-varint"
|
||||
)
|
||||
|
||||
const Prefix = "did:"
|
||||
const KeyPrefix = "did:key:"
|
||||
|
||||
const DIDCore = 0x0d1d
|
||||
const Ed25519 = 0xed
|
||||
|
||||
var MethodOffset = varint.UvarintSize(uint64(DIDCore))
|
||||
|
||||
type DID struct {
|
||||
key bool
|
||||
str string
|
||||
}
|
||||
|
||||
// Undef can be used to represent a nil or undefined DID, using DID{}
|
||||
// directly is also acceptable.
|
||||
var Undef = DID{}
|
||||
|
||||
func (d DID) Defined() bool {
|
||||
return d.str != ""
|
||||
}
|
||||
|
||||
func (d DID) Bytes() []byte {
|
||||
if !d.Defined() {
|
||||
return nil
|
||||
}
|
||||
return []byte(d.str)
|
||||
}
|
||||
|
||||
func (d DID) DID() DID {
|
||||
return d
|
||||
}
|
||||
|
||||
// String formats the decentralized identity document (DID) as a string.
|
||||
func (d DID) String() string {
|
||||
if d.key {
|
||||
key, _ := mbase.Encode(mbase.Base58BTC, []byte(d.str))
|
||||
return "did:key:" + key
|
||||
}
|
||||
return "did:" + d.str[MethodOffset:]
|
||||
}
|
||||
|
||||
func Decode(bytes []byte) (DID, error) {
|
||||
code, _, err := varint.FromUvarint(bytes)
|
||||
if err != nil {
|
||||
return Undef, err
|
||||
}
|
||||
if code == Ed25519 {
|
||||
return DID{str: string(bytes), key: true}, nil
|
||||
} else if code == DIDCore {
|
||||
return DID{str: string(bytes)}, nil
|
||||
}
|
||||
return Undef, fmt.Errorf("unsupported DID encoding: 0x%x", code)
|
||||
}
|
||||
|
||||
func Parse(str string) (DID, error) {
|
||||
if !strings.HasPrefix(str, Prefix) {
|
||||
return Undef, fmt.Errorf("must start with 'did:'")
|
||||
}
|
||||
|
||||
if strings.HasPrefix(str, KeyPrefix) {
|
||||
code, bytes, err := mbase.Decode(str[len(KeyPrefix):])
|
||||
if err != nil {
|
||||
return Undef, err
|
||||
}
|
||||
if code != mbase.Base58BTC {
|
||||
return Undef, fmt.Errorf("not Base58BTC encoded")
|
||||
}
|
||||
return Decode(bytes)
|
||||
}
|
||||
|
||||
buf := make([]byte, MethodOffset)
|
||||
varint.PutUvarint(buf, DIDCore)
|
||||
suffix, _ := strings.CutPrefix(str, Prefix)
|
||||
buf = append(buf, suffix...)
|
||||
return DID{str: string(buf)}, nil
|
||||
}
|
||||
79
did/did_test.go
Normal file
79
did/did_test.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package did
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseDIDKey(t *testing.T) {
|
||||
str := "did:key:z6Mkod5Jr3yd5SC7UDueqK4dAAw5xYJYjksy722tA9Boxc4z"
|
||||
d, err := Parse(str)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
if d.String() != str {
|
||||
t.Fatalf("expected %v to equal %v", d.String(), str)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeDIDKey(t *testing.T) {
|
||||
str := "did:key:z6Mkod5Jr3yd5SC7UDueqK4dAAw5xYJYjksy722tA9Boxc4z"
|
||||
d0, err := Parse(str)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
d1, err := Decode(d0.Bytes())
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
if d1.String() != str {
|
||||
t.Fatalf("expected %v to equal %v", d1.String(), str)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseDIDWeb(t *testing.T) {
|
||||
str := "did:web:up.web3.storage"
|
||||
d, err := Parse(str)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
if d.String() != str {
|
||||
t.Fatalf("expected %v to equal %v", d.String(), str)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeDIDWeb(t *testing.T) {
|
||||
str := "did:web:up.web3.storage"
|
||||
d0, err := Parse(str)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
d1, err := Decode(d0.Bytes())
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
if d1.String() != str {
|
||||
t.Fatalf("expected %v to equal %v", d1.String(), str)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEquivalence(t *testing.T) {
|
||||
u0 := DID{}
|
||||
u1 := Undef
|
||||
if u0 != u1 {
|
||||
t.Fatalf("undef DID not equivalent")
|
||||
}
|
||||
|
||||
d0, err := Parse("did:key:z6Mkod5Jr3yd5SC7UDueqK4dAAw5xYJYjksy722tA9Boxc4z")
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
d1, err := Parse("did:key:z6Mkod5Jr3yd5SC7UDueqK4dAAw5xYJYjksy722tA9Boxc4z")
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
if d0 != d1 {
|
||||
t.Fatalf("two equivalent DID not equivalent")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user