did

package module
v1.0.0-pre1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 5, 2025 License: Apache-2.0, MIT Imports: 8 Imported by: 0

README

go-did-it

GitHub Tag Build Status Go benchmarks Docs

This is an implementation of Decentralized Identifiers (DIDs) in go. It differs from the alternatives in the following ways:

  • simple: made of shared reusable components and clear interfaces
  • fast: while it supports DID Documents as JSON files, it's not unnecessary in the way (see below)
  • battery included: the corresponding cryptographic handling is implemented
  • support producing and using DIDs: unlike some others, this all-in-one implementation is meant to create, manipulate and handle DIDs
  • extensible: you can easily register your custom DID method

Built with ❤️ by Consensys.

Concepts

go-did-it concepts

Installation

go get github.com/MetaMask/go-did-it

Usage

Signature verification

On the verifier (~server) side, you can parse and resolve DIDs and perform signature verification:

package main

import (
	"encoding/base64"
	"fmt"

	"github.com/MetaMask/go-did-it"
	
	// 0) Import the methods you want to support
	_ "github.com/MetaMask/go-did-it/verifiers/did-key"
)

func main() {
	// 1) Parse the DID string into a DID object
	d, _ := did.Parse("did:key:z6MknwcywUtTy2ADJQ8FH1GcSySKPyKDmyzT4rPEE84XREse")

	// 2) Resolve to the DID Document
	doc, _ := d.Document()

	// 3) Use the appropriate set of verification methods (ex: verify a signature for authentication purpose)
	sig, _ := base64.StdEncoding.DecodeString("nhpkr5a7juUM2eDpDRSJVdEE++0SYqaZXHtuvyafVFUx8zsOdDSrij+vHmd/ARwUOmi/ysmSD+b3K9WTBtmmBQ==")
	if ok, method := did.TryAllVerify(doc.Authentication(), []byte("message"), sig); ok {
		fmt.Println("Signature is valid, verified with method:", method.Type(), method.ID())
	} else {
		fmt.Println("Signature is invalid")
	}

	// Output: Signature is valid, verified with method: Ed25519VerificationKey2020 did:key:z6MknwcywUtTy2ADJQ8FH1GcSySKPyKDmyzT4rPEE84XREse#z6MknwcywUtTy2ADJQ8FH1GcSySKPyKDmyzT4rPEE84XREse
}

Key agreement

You can also compute a shared secret to bootstrap an encrypted communication protocol.

⚠️ Security Warning: The shared secret returned by key agreement should NOT be used directly as an encryption key. It must be processed through a Key Derivation Function (KDF) such as HKDF before being used in cryptographic protocols. Using the raw shared secret directly can lead to security vulnerabilities.

package main

import (
	"encoding/base64"
	"fmt"

	"github.com/MetaMask/go-did-it"
	"github.com/MetaMask/go-did-it/crypto/x25519"

	// 0) Import the methods you want to support
	_ "github.com/MetaMask/go-did-it/verifiers/did-key"
)

func main() {
	// 1) We have a private key for Alice
	privAliceBytes, _ := base64.StdEncoding.DecodeString("fNOf3xWjFZYGYWixorM5+JR+u/2Udnc9Zw5+9rSvjqo=")
	privAlice, _ := x25519.PrivateKeyFromBytes(privAliceBytes)

	// 2) We resolve the DID Document for Bob
	dBob, _ := did.Parse("did:key:z6MkgRNXpJRbEE6FoXhT8KWHwJo4KyzFo1FdSEFpRLh5vuXZ")
	docBob, _ := dBob.Document()

	// 3) We perform the key agreement
	key, method, _ := did.FindMatchingKeyAgreement(docBob.KeyAgreement(), privAlice)

	fmt.Println("Shared key:", base64.StdEncoding.EncodeToString(key))
	fmt.Println("Verification method used:", method.Type(), method.ID())

	// Output: Shared key: 7G1qwS/gn5W1hxBtObHc3F0jA7m2vuXkLJJ32yBuHVQ=
	// Verification method used: X25519KeyAgreementKey2020 did:key:z6MkgRNXpJRbEE6FoXhT8KWHwJo4KyzFo1FdSEFpRLh5vuXZ#z6LSjeQx2VkXz8yirhrYJv8uicu9BBaeYU3Q1D9sFBovhmPF
}

Features

Supported DID Methods

Method Controller Verifier Description
did:key Self-contained DIDs based on public keys
did:web DID document resolved with HTTP
did:plc Bluesky's DID with rotation and a public directory

Supported Verification Method Types

Type Use Case
EcdsaSecp256k1VerificationKey2019 secp256k1 signatures
Ed25519VerificationKey2018 Ed25519 signatures
Ed25519VerificationKey2020 Ed25519 signatures
JsonWebKey2020 All supported algorithms
Multikey All supported algorithms
P256Key2021 P-256 signatures
X25519KeyAgreementKey2020 X25519 key agreement

Supported Cryptographic Algorithms

Algorithm Signature Format Public Key Formats Private Key Formats Key Agreement
Ed25519 Raw bytes, ASN.1 Raw bytes, X.509 DER/PEM, Multibase Raw bytes, PKCS#8 DER/PEM ✅ (via X25519)
ECDSA P-256 Raw bytes, ASN.1 Raw bytes, X.509 DER/PEM, Multibase Raw bytes, PKCS#8 DER/PEM
ECDSA P-384 Raw bytes, ASN.1 Raw bytes, X.509 DER/PEM, Multibase Raw bytes, PKCS#8 DER/PEM
ECDSA P-521 Raw bytes, ASN.1 Raw bytes, X.509 DER/PEM, Multibase Raw bytes, PKCS#8 DER/PEM
ECDSA secp256k1 Raw bytes, ASN.1 Raw bytes, X.509 DER/PEM, Multibase Raw bytes, PKCS#8 DER/PEM
RSA PKCS#1 v1.5 ASN.1 X.509 DER/PEM, Multibase PKCS#8 DER/PEM
X25519 Raw bytes, X.509 DER/PEM, Multibase Raw bytes, PKCS#8 DER/PEM

Documentation

Overview

Example (KeyAgreement)
// errors need to be handled

// 1) We have a private key for Alice
privAliceBytes, _ := base64.StdEncoding.DecodeString("fNOf3xWjFZYGYWixorM5+JR+u/2Udnc9Zw5+9rSvjqo=")
privAlice, _ := x25519.PrivateKeyFromBytes(privAliceBytes)

// 2) We resolve the DID Document for Bob
dBob, _ := did.Parse("did:key:z6MkgRNXpJRbEE6FoXhT8KWHwJo4KyzFo1FdSEFpRLh5vuXZ")
docBob, _ := dBob.Document()

// 3) We perform the key agreement
key, method, _ := did.FindMatchingKeyAgreement(docBob.KeyAgreement(), privAlice)

fmt.Println("Shared key:", base64.StdEncoding.EncodeToString(key))
fmt.Println("Verification method used:", method.Type(), method.ID())
Output:

Shared key: 7G1qwS/gn5W1hxBtObHc3F0jA7m2vuXkLJJ32yBuHVQ=
Verification method used: X25519KeyAgreementKey2020 did:key:z6MkgRNXpJRbEE6FoXhT8KWHwJo4KyzFo1FdSEFpRLh5vuXZ#z6LSjeQx2VkXz8yirhrYJv8uicu9BBaeYU3Q1D9sFBovhmPF
Example (Signature)
// errors need to be handled

// 1) Parse the DID string into a DID object
d, _ := did.Parse("did:key:z6MknwcywUtTy2ADJQ8FH1GcSySKPyKDmyzT4rPEE84XREse")

// 2) Resolve to the DID Document
doc, _ := d.Document()

// 3) Use the appropriate set of verification methods (ex: verify a signature for authentication purpose)
sig, _ := base64.StdEncoding.DecodeString("nhpkr5a7juUM2eDpDRSJVdEE++0SYqaZXHtuvyafVFUx8zsOdDSrij+vHmd/ARwUOmi/ysmSD+b3K9WTBtmmBQ==")
if ok, method := did.TryAllVerifyBytes(doc.Authentication(), []byte("message"), sig); ok {
	fmt.Println("Signature is valid, verified with method:", method.Type(), method.ID())
} else {
	fmt.Println("Signature is invalid")
}
Output:

Signature is valid, verified with method: Ed25519VerificationKey2020 did:key:z6MknwcywUtTy2ADJQ8FH1GcSySKPyKDmyzT4rPEE84XREse#z6MknwcywUtTy2ADJQ8FH1GcSySKPyKDmyzT4rPEE84XREse

Index

Examples

Constants

View Source
const JsonLdContext = "https://www.w3.org/ns/did/v1"

Variables

View Source
var (
	// ErrInvalidDid indicates that the DID supplied to the DID resolution function does not conform to valid syntax.
	ErrInvalidDid = fmt.Errorf("invalid DID")

	// ErrMethodNotSupported indicates that the DID method is not supported, or that the corresponding decoder
	// has not been registered properly.
	ErrMethodNotSupported = fmt.Errorf("DID method not supported")
)

Decoder errors

View Source
var (
	// ErrNotFound indicates that the DID resolver was unable to find the DID document for the given DID.
	ErrNotFound = fmt.Errorf("did not found")

	// ErrResolutionFailure indicates that the DID resolver failed to resolve the DID, in a way that is not ErrNotFound
	ErrResolutionFailure = fmt.Errorf("resolution failure")
)

Resolver errors

Functions

func HasValidDIDSyntax

func HasValidDIDSyntax(didStr string) bool

HasValidDIDSyntax tells if the given string representation conforms to DID syntax. This does NOT verify that the method is supported by this library.

func HasValidDidUrlSyntax

func HasValidDidUrlSyntax(didUrlStr string) bool

HasValidDidUrlSyntax tells if the given string representation conforms to DID URL syntax. This does NOT verify that the method is supported by this library.

func RegisterMethod

func RegisterMethod(method string, decoder Decoder)

RegisterMethod registers a DID decoder for a given DID method. Method must be the DID method (for example, "key" in did:key).

Types

type DID

type DID interface {
	// Method returns the name of the DID method (e.g. "key" for did:key).
	Method() string

	// Document resolves the DID into a DID Document usable for e.g. signature check.
	// This can be simply expanding the DID into a Document, or involve external resolution.
	Document(opts ...ResolutionOption) (Document, error)

	// String returns the string representation of the DID.
	String() string

	// 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 returns true if this and the given DID are the same.
	Equal(DID) bool
}

DID is a decoded (i.e. from a string) Decentralized Identifier.

func MustParse

func MustParse(didStr string) DID

MustParse is like Parse but panics instead of returning an error.

func Parse

func Parse(didStr string) (DID, error)

Parse attempts to decode a DID from its string representation.

type Decoder

type Decoder func(didStr string) (DID, error)

Decoder is a function decoding a DID string representation ("did:example:foo") into a DID.

type Document

type Document interface {
	json.Marshaler

	// Context is the set of JSON-LD context documents.
	Context() []string

	// ID is the identifier of the Document, which is the DID itself as string.
	ID() string

	// Controllers is the set of DID that is authorized to make changes to the Document. It's often the same as ID.
	Controllers() []string

	// AlsoKnownAs returns an optional set of URL describing different identifier for the DID subject,
	// for different purpose or different time.
	AlsoKnownAs() []*url.URL

	// VerificationMethods returns all the VerificationMethod known in the document.
	VerificationMethods() map[string]VerificationMethod

	// Authentication defines how the DID is able to authenticate, for purposes such as logging into a website
	// or engaging in any sort of challenge-response protocol.
	Authentication() []VerificationMethodSignature

	// Assertion specifies how the DID subject is expected to express claims, such as for the purposes of issuing
	// a Verifiable Credential.
	// See https://www.w3.org/TR/vc-data-model/
	Assertion() []VerificationMethodSignature

	// KeyAgreement specifies how an entity can generate encryption material in order to transmit confidential
	// information intended for the DID subject, such as for the purposes of establishing a secure communication channel
	// with the recipient.
	KeyAgreement() []VerificationMethodKeyAgreement

	// CapabilityInvocation specifies a verification method that might be used by the DID subject to invoke a
	// cryptographic capability, such as the authorization to update the DID Document.
	CapabilityInvocation() []VerificationMethodSignature

	// CapabilityDelegation specifies a mechanism that might be used by the DID subject to delegate a cryptographic
	// capability to another party, such as delegating the authority to access a specific HTTP API to a subordinate.
	CapabilityDelegation() []VerificationMethodSignature

	// Services are means of communicating or interacting with the DID subject or associated entities
	// via one or more endpoints. Examples include discovery services, agent services, social networking
	// services, file storage services, and verifiable credential repository services.
	Services() Services
}

Document is the interface for a DID document. It represents the "resolved" state of a DID.

type HttpClient

type HttpClient interface {
	Do(req *http.Request) (*http.Response, error)
}

type MapEndpoint

type MapEndpoint map[string]any

type ResolutionOption

type ResolutionOption func(opts *ResolutionOpts)

func WithHttpClient

func WithHttpClient(client HttpClient) ResolutionOption

WithHttpClient provides an HttpClient to be used during resolution.

func WithResolutionContext

func WithResolutionContext(ctx context.Context) ResolutionOption

WithResolutionContext provides a go context to use for the resolution. This context can be used for deadline or cancellation.

func WithResolutionHintVerificationMethod

func WithResolutionHintVerificationMethod(hint string) ResolutionOption

WithResolutionHintVerificationMethod adds a hint for the type of verification method to be used when resolving and constructing the DID Document, if possible. Hints are expected to be VerificationMethod string types, like ed25519vm.Type.

type ResolutionOpts

type ResolutionOpts struct {
	// contains filtered or unexported fields
}

func CollectResolutionOpts

func CollectResolutionOpts(opts []ResolutionOption) ResolutionOpts

func (*ResolutionOpts) Context

func (opts *ResolutionOpts) Context() context.Context

func (*ResolutionOpts) HasVerificationMethodHint

func (opts *ResolutionOpts) HasVerificationMethodHint(hint string) bool

func (*ResolutionOpts) HttpClient

func (opts *ResolutionOpts) HttpClient() HttpClient

type Service

type Service struct {
	Id        string
	Types     []string
	Endpoints []any // either strEndpoint or mapEndpoint
}

Service is a means of communicating or interacting with the DID subject or associated entities via one or more service endpoints. It can have one or more types.

func (Service) HasType

func (s Service) HasType(_type string) bool

func (Service) MarshalJSON

func (s Service) MarshalJSON() ([]byte, error)

func (*Service) UnmarshalJSON

func (s *Service) UnmarshalJSON(bytes []byte) error

type Services

type Services []Service

Services is a collection of Service.

func (Services) ServiceById

func (ss Services) ServiceById(id string) (Service, bool)

ServiceById retrieves a Service from the Services slice by its id. Returns the Service and true if found, otherwise returns an empty Service and false.

func (Services) ServiceByType

func (ss Services) ServiceByType(_type string) (Service, bool)

ServiceByType returns zero or one Service matching the given type. If there is more than one service for that type, the first match is returned.

type StrEndpoint

type StrEndpoint string

type VerificationMethod

type VerificationMethod interface {
	json.Marshaler
	json.Unmarshaler

	// ID is a string identifier for the VerificationMethod. It can be referenced in a Document.
	ID() string

	// Type is a string identifier of a verification method.
	// See https://www.w3.org/TR/did-extensions-properties/#verification-method-types
	Type() string

	// Controller is a DID able to control the VerificationMethod.
	// This is not necessarily the same as for DID itself or the Document.
	Controller() string

	// JsonLdContext reports the JSON-LD context definition required for this verification method.
	JsonLdContext() string
}

VerificationMethod is a common interface for a cryptographic signature verification method. For example, Ed25519VerificationKey2020 implements the Ed25519 signature verification.

type VerificationMethodKeyAgreement

type VerificationMethodKeyAgreement interface {
	VerificationMethod

	// PrivateKeyIsCompatible checks that the given PrivateKey is compatible with this method.
	PrivateKeyIsCompatible(local crypto.PrivateKeyKeyExchange) bool

	// KeyExchange computes the shared key using the given PrivateKey.
	KeyExchange(local crypto.PrivateKeyKeyExchange) ([]byte, error)
}

VerificationMethodKeyAgreement is a VerificationMethod implementing a shared key agreement. It can be used for KeyAgreement in a Document.

func FindMatchingKeyAgreement

FindMatchingKeyAgreement tries to find a matching key agreement method for the given private key type. It returns the shared key as well as the selected method. If no matching method is found, it returns an error.

type VerificationMethodSignature

type VerificationMethodSignature interface {
	VerificationMethod

	// VerifyBytes checks that 'sig' is a valid "raw bytes" signature of 'data'.
	VerifyBytes(data []byte, sig []byte, opts ...crypto.SigningOption) (bool, error)

	// VerifyASN1 checks that 'sig' is a valid ASN.1 signature of 'data'.
	VerifyASN1(data []byte, sig []byte, opts ...crypto.SigningOption) (bool, error)
}

VerificationMethodSignature is a VerificationMethod implementing signature verification. It can be used for Authentication, Assertion, CapabilityInvocation, CapabilityDelegation in a Document.

func TryAllVerifyASN1

func TryAllVerifyASN1(methods []VerificationMethodSignature, data []byte, sig []byte, opts ...crypto.SigningOption) (bool, VerificationMethodSignature)

TryAllVerifyASN1 tries to verify the signature as ASN.1 with all the methods in the slice. It returns true if the signature is verified, and the method that verified it. If no method verifies the signature, it returns false and nil.

func TryAllVerifyBytes

func TryAllVerifyBytes(methods []VerificationMethodSignature, data []byte, sig []byte, opts ...crypto.SigningOption) (bool, VerificationMethodSignature)

TryAllVerifyBytes tries to verify the signature as bytes with all the methods in the slice. It returns true if the signature is verified, and the method that verified it. If no method verifies the signature, it returns false and nil.

Directories

Path Synopsis
controller
jwk
rsa
Package didtest provides Personas that can be used for testing.
Package didtest provides Personas that can be used for testing.
verifiers

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL