79 Commits

Author SHA1 Message Date
Michael Muré
a7e698e4ec toolkit/client: fix FindProof to handle self-delegation properly 2025-12-08 20:25:28 +01:00
Michael Muré
4b3a0c590a invocation: add support for self-signed invocations (issuer=subject) 2025-12-08 18:11:58 +01:00
Michael Muré
4b99c9f1df Merge pull request #118 from alanshaw/ash/fix/sort-tokens
fix: sort tokens
2025-12-03 17:04:04 +01:00
Michael Muré
39694340cd Merge pull request #117 from ucan-wg/ash/fix/licence-name
fix: license name
2025-12-03 13:32:54 +01:00
Alan Shaw
e93e464977 fix: sort tokens 2025-12-03 12:19:27 +00:00
ash
823af27272 fix: license name
License is Apache-2.0 **OR** MIT i.e. not "and"/"+"

Signed-off-by: ash <alan138@gmail.com>
2025-11-02 22:02:28 +00:00
Michael Muré
70f039a654 update Readme 2025-10-29 15:48:15 +01:00
Michael Muré
d56db6722c Merge pull request #115 from ucan-wg/tooling
Add a somewhat complete toolkit
2025-08-07 14:39:42 +02:00
Michael Muré
0647e4ff8a adjust the toolkit to the new location 2025-08-07 14:28:16 +02:00
Steve Moyer
06f478b9c3 feat(client): add delegation bundle(s) to client.pool 2025-08-05 16:57:19 +02:00
Michael Muré
4aedc4de39 client: add a convenient PrepareDelegation function 2025-08-05 16:57:19 +02:00
Michael Muré
0fd71612d3 exectx: DX improvement: catch proof chain issue early 2025-08-05 16:57:19 +02:00
Michael Muré
29ccdb700e exectx: more tests 2025-08-05 16:57:19 +02:00
Michael Muré
2d031fdbdb exectx: easy access to the root delegation 2025-08-05 16:57:19 +02:00
Michael Muré
1c4a0a9c81 exectx: add test for the main middleware, adjust some HTTP status 2025-08-05 16:57:19 +02:00
Michael Muré
df6dfee210 example: finish readme, small tuning 2025-08-05 16:57:19 +02:00
Michael Muré
c670433335 example: add sub-delegation 2025-08-05 16:57:19 +02:00
Michael Muré
55f38fef4a add server/issuer/client examples, and lots of sanding 2025-08-05 16:57:19 +02:00
Michael Muré
1098a834fb bearer: add some tests 2025-08-05 16:57:19 +02:00
Michael Muré
b95e525cfb exectx: add a minimal middleware to extract the HTTP bearer, and make the UCAN ctx 2025-08-05 16:57:19 +02:00
Michael Muré
cc207aa202 bearer: add a package to add/extract a HTTP Authorisation bearer header 2025-08-05 16:57:19 +02:00
Michael Muré
41d679dfab extargs: make the hash more convenient to use by directly returning the invocation.Option 2025-08-05 16:57:19 +02:00
Michael Muré
cc661f3936 infura requester: properly handle failure 2025-08-05 16:57:19 +02:00
Michael Muré
07d2745966 client,step1: add a KS compatible client, and a script to package tokens for PC step1 2025-08-05 16:57:19 +02:00
rarquevaux
cd9ee535ad fix(ucanCtx): update test 2025-08-05 16:57:19 +02:00
rarquevaux
9e062b0cc7 fix(ucanCtx): pointer receiver and fix to verifyHttp 2025-08-05 16:57:19 +02:00
Michael Muré
cf3eb1b3f7 bump go-ucan 2025-08-05 16:57:19 +02:00
Michael Muré
3b6d70f47a extargs: add ".inf" external args for arbitrary Infura args 2025-08-05 16:57:19 +02:00
Michael Muré
09c8815755 update go-ucan, with the now spec defined container
https://github.com/ucan-wg/go-ucan/blob/main/pkg/container/SPEC.md
2025-08-05 16:57:19 +02:00
Michael Muré
f18ae547ab Update server/extargs/http.go
Co-authored-by: Steve Moyer <smoyer64@gmail.com>
2025-08-05 16:57:19 +02:00
Michael Muré
ad02aa8d4f server: rename "bearer" package to "extargs" 2025-08-05 16:57:19 +02:00
Michael Muré
9c8e9f17fa cli: update following go-ucan changes 2025-08-05 16:57:19 +02:00
Michael Muré
11b4352063 client: fix FindProof() 2025-08-05 16:57:19 +02:00
Michael Muré
b0783bf4a4 add a "core" implementation of an issuer 2025-08-05 16:57:19 +02:00
Michael Muré
2eeaaccc6d client: follow go-ucan changes, improvements, example 2025-08-05 16:57:19 +02:00
Michael Muré
1187674a24 server: minor code fixes 2025-08-05 16:57:19 +02:00
Michael Muré
4c08b22c61 add an early version of a UCAN client 2025-08-05 16:57:19 +02:00
Michael Muré
174bf01c64 client: simpler FindProof() 2025-08-05 16:57:19 +02:00
Michael Muré
4167bf44bd reorg packages, remove outdated server example 2025-08-05 16:57:19 +02:00
Michael Muré
4f4331b677 client: move FindProof testing directly where the code is 2025-08-05 16:57:19 +02:00
Michael Muré
547416e60d client: improve/modularize 2025-08-05 16:57:19 +02:00
Michael Muré
6c1602507b client: add a pool that can find a prood for an invocation 2025-08-05 16:57:19 +02:00
Michael Muré
6f4853cd2f bearer,context: support hash verification of the computed args 2025-08-05 16:57:19 +02:00
Michael Muré
4c25456583 server: update deps 2025-08-05 16:57:19 +02:00
Michael Muré
83f3e4c3b0 server: add a readme 2025-08-05 16:57:19 +02:00
Michael Muré
1178e51b18 server: add a WIP middleware example 2025-08-05 16:57:19 +02:00
Michael Muré
3ec8f56412 Merge pull request #114 from ucan-wg/varsig-did
Integrate go-varsig and go-did-it
2025-08-05 16:56:51 +02:00
Michael Muré
5891bdcd5d update go-varsig, go-did-it, add missing resolution options 2025-08-05 16:54:18 +02:00
Michael Muré
6fb25481ce delegation: add interop testing 2025-08-04 16:45:49 +02:00
Michael Muré
e7edccdd71 wire the DID resolution options 2025-07-31 17:49:01 +02:00
Michael Muré
33e8a8a821 Integrate go-varsig and go-did-it
- go-varsig provides a varsig V1 implementation
- go-did-it provides a complete and extensible DID implementation
2025-07-31 15:00:31 +02:00
Steve Moyer
947add66c5 Merge pull request #112 from ucan-wg/fix/invokedat-to-issued-at
fix(invocation): iat incorrectly named InvokedAt instead of IssuedAt
2025-03-11 13:20:25 -04:00
Steve Moyer
3faf9d598c fix(invocation): also update docs and examples 2025-03-11 13:14:53 -04:00
Steve Moyer
fbf55e98ba Update token/invocation/options.go
Co-authored-by: Michael Muré <batolettre@gmail.com>
Signed-off-by: Steve Moyer <smoyer64@gmail.com>
2025-03-11 12:57:08 -04:00
Steve Moyer
05c2573d95 Update token/invocation/options.go
Co-authored-by: Michael Muré <batolettre@gmail.com>
Signed-off-by: Steve Moyer <smoyer64@gmail.com>
2025-03-11 12:56:49 -04:00
Steve Moyer
d7472621ce Update token/invocation/invocation.go
Co-authored-by: Michael Muré <batolettre@gmail.com>
Signed-off-by: Steve Moyer <smoyer64@gmail.com>
2025-03-11 12:56:34 -04:00
Steve Moyer
7b44f480ee fix(invocation): iat incorrectly named InvokedAt instead of IssuedAt 2025-03-11 12:41:24 -04:00
Michael Muré
5eb7b1a8e4 Merge pull request #111 from ucan-wg/MichaelMure-patch-1
container: typo fix in SPEC.md
2025-03-11 17:34:08 +01:00
Michael Muré
e91afe29d8 Update SPEC.md
Signed-off-by: Michael Muré <batolettre@gmail.com>
2025-03-11 17:32:17 +01:00
Michael Muré
a82bce556f Merge pull request #108 from ucan-wg/cont-test
container: add a helper for test only
2025-02-27 15:00:47 +01:00
Michael Muré
a54d66afe5 Merge pull request #110 from ucan-wg/cleanups
minor cleanups
2025-02-27 14:58:24 +01:00
Michael Muré
14a57d7391 Merge pull request #109 from ucan-wg/downgrade-libp2p
deps: downgrade libp2p
2025-02-27 14:58:17 +01:00
Michael Muré
68469db91a minor cleanups 2025-02-27 14:35:53 +01:00
Michael Muré
cc1d68be0c deps: downgrade libp2p
We only use go-libp2p for the crypto wrappers (github.com/libp2p/go-libp2p/core/crypto), and those have not changed in a while.

We don't need the most recent version of go-libp2p. On the other hand, a too recent version can easily mess with project that aim for an older version of libp2p (often transitively). This PR gives some leeway for version resolution.
2025-02-27 14:28:23 +01:00
Michael Muré
6d3846ac62 container: add a helper for test only 2025-02-27 14:27:02 +01:00
Steve Moyer
6aa33b1547 Merge pull request #107 from ucan-wg/tinygo
fix(policy): make 53-bit limits portable across platforms
2025-02-24 06:25:06 -05:00
Steve Moyer
9589cc8b44 feat(tinygo): make 53-bit limits portable across platforms 2025-02-21 11:03:33 -05:00
Michael Muré
879c0ab03b Merge pull request #106 from ucan-wg/cont-type
container: use the correct type in GetAllDelegations
2025-02-03 15:13:05 +01:00
Michael Muré
fe14765c8d container: use the correct type in GetAllDelegations 2025-02-03 15:02:31 +01:00
Michael Muré
1b28cb49bf Merge pull request #105 from ucan-wg/containertest
rename testvectors into containertest to match previous namings
2025-01-29 15:04:33 +01:00
Michael Muré
e1fc838caf rename testvectors into containertest to match previous namings 2025-01-29 14:46:01 +01:00
Michael Muré
f29b9e94fc Merge pull request #104 from ucan-wg/bundle
token: ditch the generic bundle in favor of specialized struct
2025-01-29 14:37:29 +01:00
Michael Muré
506ed21b94 token: ditch the generic bundle in favor of specialized struct
It's kust cleaner that way, the generic has no upside.
2025-01-29 14:28:13 +01:00
Michael Muré
126177b9e5 Merge pull request #103 from ucan-wg/dlg-is
delegation: add predicates to check if a delegation is a root or powe…
2025-01-29 14:11:29 +01:00
Michael Muré
2bddab8b0c delegation: add predicates to check if a delegation is a root or powerline 2025-01-29 14:07:49 +01:00
Michael Muré
45ead12131 Merge pull request #102 from ucan-wg/cont-keep-sealed
container: Reader should keep around and expose the sealed bytes
2025-01-23 18:06:41 +01:00
Michael Muré
9d5e170409 Merge pull request #101 from ucan-wg/cont-testing
container: expose test vectors for easier testing
2025-01-23 18:06:27 +01:00
Michael Muré
9d047f038d container: Reader should keep around and expose the sealed bytes 2025-01-23 17:13:10 +01:00
Michael Muré
4c5afcb084 container: expose test vectors for easier testing 2025-01-23 17:10:34 +01:00
142 changed files with 3990 additions and 3291 deletions

View File

@@ -17,7 +17,7 @@
<img alt="Go benchmarks" src="https://img.shields.io/badge/Benchmarks-go-blue">
</a>
<a href="https://github.com/ucan-wg/go-ucan/blob/v1/LICENSE.md">
<img alt="Apache 2.0 + MIT License" src="https://img.shields.io/badge/License-Apache--2.0+MIT-green">
<img alt="Apache 2.0 OR MIT License" src="https://img.shields.io/badge/License-Apache--2.0_OR_MIT-green">
</a>
<a href="https://pkg.go.dev/github.com/ucan-wg/go-ucan">
<img src="https://img.shields.io/badge/Docs-godoc-blue" alt="Docs">
@@ -41,6 +41,7 @@ The UCAN specification is separated in multiple sub-spec:
- [Main specification](https://github.com/ucan-wg/spec)
- [Delegation](https://github.com/ucan-wg/delegation/tree/v1_ipld)
- [Invocation](https://github.com/ucan-wg/invocation)
- [Container](https://github.com/ucan-wg/container)
Not implemented yet:
- [Revocation](https://github.com/ucan-wg/revocation/tree/first-draft)
@@ -53,11 +54,9 @@ Not implemented yet:
## Status
`go-ucan` currently support the required parts of the UCAN specification: the main specification, delegation and invocation.
`go-ucan` currently support the required parts of the UCAN specification: the main specification, delegation and invocation. It leverages the sibling project [`go-did-it`](https://github.com/MetaMask/go-did-it) for easy and extensible DID support.
Besides that, `go-ucan` also includes:
- a simplified [DID](https://www.w3.org/TR/did-core/) and [did-key](https://w3c-ccg.github.io/did-method-key/) implementation
- a [token container](https://github.com/ucan-wg/go-ucan/tree/v1/pkg/container) with CBOR and CAR format, to package and carry tokens together, see [SPEC](pkg/container/SPEC.md)
- support for encrypted values in token's metadata
## Getting Help
@@ -74,4 +73,4 @@ Artwork by [Bruno Monts](https://www.instagram.com/bruno_monts). Thank you [Rene
## License
This project is licensed under the double license [Apache 2.0 + MIT](https://github.com/ucan-wg/go-ucan/blob/v1/LICENSE.md).
This project is licensed under the dual license [Apache 2.0 OR MIT](https://github.com/ucan-wg/go-ucan/blob/v1/LICENSE.md).

View File

@@ -1,31 +0,0 @@
## did
### Testing
The test suite for this package includes test vectors provided by the
authors of the [`did:key` method specification](https://w3c-ccg.github.io/did-method-key/).
Some of these tests provide the public key associated with a `did:key`
as JWKs and an extra (test-only) dependency has been added to unmarshal
the JWK into a Go `struct`. Support for the `secp256k1` encryption
algorithm is experimental (but stable in my experience) and requires the
addition of the following build tag to properly run:
```
// go:build jwx_es256k
```
WARNING: These tests will not run by default!
To include these tests from the CLI, execute the following command:
```
go test -v ./did -tags jwx_es256k
```
It should also be possible to configure your IDE to run these tests. For
instance, in Codium, add the following JSON snippet to your local project
configuration:
```
"go.testTags": "jwx_es256k",
```

View File

@@ -1,231 +0,0 @@
package did
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"errors"
"fmt"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
crypto "github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/crypto/pb"
"github.com/multiformats/go-multicodec"
"github.com/multiformats/go-varint"
)
// GenerateEd25519 generates an Ed25519 private key and the matching DID.
// This is the RECOMMENDED algorithm.
func GenerateEd25519() (crypto.PrivKey, DID, error) {
priv, pub, err := crypto.GenerateEd25519Key(rand.Reader)
if err != nil {
return nil, Undef, nil
}
did, err := FromPubKey(pub)
return priv, did, err
}
// GenerateRSA generates a RSA private key and the matching DID.
func GenerateRSA() (crypto.PrivKey, DID, error) {
// NIST Special Publication 800-57 Part 1 Revision 5
// Section 5.6.1.1 (Table 2)
// Paraphrased: 2048-bit RSA keys are secure until 2030 and 3072-bit keys are recommended for longer-term security.
const keyLength = 3072
priv, pub, err := crypto.GenerateRSAKeyPair(keyLength, rand.Reader)
if err != nil {
return nil, Undef, nil
}
did, err := FromPubKey(pub)
return priv, did, err
}
// GenerateEd25519 generates a Secp256k1 private key and the matching DID.
func GenerateSecp256k1() (crypto.PrivKey, DID, error) {
priv, pub, err := crypto.GenerateSecp256k1Key(rand.Reader)
if err != nil {
return nil, Undef, nil
}
did, err := FromPubKey(pub)
return priv, did, err
}
// GenerateECDSA generates an ECDSA private key and the matching DID
// for the default P256 curve.
func GenerateECDSA() (crypto.PrivKey, DID, error) {
return GenerateECDSAWithCurve(P256)
}
// GenerateECDSAWithCurve generates an ECDSA private key and matching
// DID for the user-supplied curve
func GenerateECDSAWithCurve(code multicodec.Code) (crypto.PrivKey, DID, error) {
var curve elliptic.Curve
switch code {
case P256:
curve = elliptic.P256()
case P384:
curve = elliptic.P384()
case P521:
curve = elliptic.P521()
default:
return nil, Undef, errors.New("unsupported ECDSA curve")
}
priv, pub, err := crypto.GenerateECDSAKeyPairWithCurve(curve, rand.Reader)
if err != nil {
return nil, Undef, err
}
did, err := FromPubKey(pub)
return priv, did, err
}
// FromPrivKey is a convenience function that returns the DID associated
// with the public key associated with the provided private key.
func FromPrivKey(privKey crypto.PrivKey) (DID, error) {
return FromPubKey(privKey.GetPublic())
}
// FromPubKey returns a did:key constructed from the provided public key.
func FromPubKey(pubKey crypto.PubKey) (DID, error) {
var code multicodec.Code
switch pubKey.Type() {
case pb.KeyType_Ed25519:
code = multicodec.Ed25519Pub
case pb.KeyType_RSA:
code = RSA
case pb.KeyType_Secp256k1:
code = Secp256k1
case pb.KeyType_ECDSA:
var err error
if code, err = codeForCurve(pubKey); err != nil {
return Undef, err
}
default:
return Undef, errors.New("unsupported key type")
}
if pubKey.Type() == pb.KeyType_ECDSA && code == Secp256k1 {
var err error
pubKey, err = coerceECDSAToSecp256k1(pubKey)
if err != nil {
return Undef, err
}
}
var bytes []byte
switch pubKey.Type() {
case pb.KeyType_ECDSA:
pkix, err := pubKey.Raw()
if err != nil {
return Undef, err
}
publicKey, err := x509.ParsePKIXPublicKey(pkix)
if err != nil {
return Undef, err
}
ecdsaPublicKey := publicKey.(*ecdsa.PublicKey)
bytes = elliptic.MarshalCompressed(ecdsaPublicKey.Curve, ecdsaPublicKey.X, ecdsaPublicKey.Y)
case pb.KeyType_Ed25519, pb.KeyType_Secp256k1:
var err error
if bytes, err = pubKey.Raw(); err != nil {
return Undef, err
}
case pb.KeyType_RSA:
var err error
pkix, err := pubKey.Raw()
if err != nil {
return Undef, err
}
publicKey, err := x509.ParsePKIXPublicKey(pkix)
if err != nil {
return Undef, err
}
bytes = x509.MarshalPKCS1PublicKey(publicKey.(*rsa.PublicKey))
}
return DID{
code: code,
bytes: string(append(varint.ToUvarint(uint64(code)), bytes...)),
}, nil
}
// ToPubKey returns the crypto.PubKey encapsulated in the DID formed by
// parsing the provided string.
func ToPubKey(s string) (crypto.PubKey, error) {
id, err := Parse(s)
if err != nil {
return nil, err
}
return id.PubKey()
}
func codeForCurve(pubKey crypto.PubKey) (multicodec.Code, error) {
stdPub, err := crypto.PubKeyToStdKey(pubKey)
if err != nil {
return multicodec.Identity, err
}
ecdsaPub, ok := stdPub.(*ecdsa.PublicKey)
if !ok {
return multicodec.Identity, errors.New("failed to assert type for code to curve")
}
switch ecdsaPub.Curve {
case elliptic.P256():
return P256, nil
case elliptic.P384():
return P384, nil
case elliptic.P521():
return P521, nil
case secp256k1.S256():
return Secp256k1, nil
default:
return multicodec.Identity, fmt.Errorf("unsupported ECDSA curve: %s", ecdsaPub.Curve.Params().Name)
}
}
// secp256k1.S256 is a valid ECDSA curve, but the go-libp2p/core/crypto
// package treats it as a different type and has a different format for
// the raw bytes of the public key.
//
// If a valid ECDSA public key was created using the secp256k1.S256 curve,
// this function will "convert" it from a crypto.ECDSAPubKey to a
// crypto.Secp256k1PublicKey.
func coerceECDSAToSecp256k1(pubKey crypto.PubKey) (crypto.PubKey, error) {
stdPub, err := crypto.PubKeyToStdKey(pubKey)
if err != nil {
return nil, err
}
ecdsaPub, ok := stdPub.(*ecdsa.PublicKey)
if !ok {
return nil, errors.New("failed to assert type for secp256k1 coersion")
}
ecdsaPubBytes := append([]byte{0x04}, append(ecdsaPub.X.Bytes(), ecdsaPub.Y.Bytes()...)...)
secp256k1Pub, err := secp256k1.ParsePubKey(ecdsaPubBytes)
if err != nil {
return nil, err
}
cryptoPub := crypto.Secp256k1PublicKey(*secp256k1Pub)
return &cryptoPub, nil
}

View File

@@ -1,108 +0,0 @@
package did_test
import (
"crypto/elliptic"
"crypto/rand"
"testing"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/crypto/pb"
"github.com/multiformats/go-multicodec"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/ucan-wg/go-ucan/did"
)
const (
exampleDIDStr = "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK"
examplePubKeyStr = "Lm/M42cB3HkUiODQsXRcweM6TByfzEHGO9ND274JcOY="
)
func TestFromPubKey(t *testing.T) {
t.Parallel()
_, ecdsaP256, err := crypto.GenerateECDSAKeyPairWithCurve(elliptic.P256(), rand.Reader)
require.NoError(t, err)
_, ecdsaP384, err := crypto.GenerateECDSAKeyPairWithCurve(elliptic.P384(), rand.Reader)
require.NoError(t, err)
_, ecdsaP521, err := crypto.GenerateECDSAKeyPairWithCurve(elliptic.P521(), rand.Reader)
require.NoError(t, err)
_, ecdsaSecp256k1, err := crypto.GenerateECDSAKeyPairWithCurve(secp256k1.S256(), rand.Reader)
require.NoError(t, err)
_, ed25519, err := crypto.GenerateEd25519Key(rand.Reader)
require.NoError(t, err)
_, rsa, err := crypto.GenerateRSAKeyPair(2048, rand.Reader)
require.NoError(t, err)
_, secp256k1PubKey1, err := crypto.GenerateSecp256k1Key(rand.Reader)
require.NoError(t, err)
test := func(pub crypto.PubKey, code multicodec.Code) func(t *testing.T) {
t.Helper()
return func(t *testing.T) {
t.Parallel()
id, err := did.FromPubKey(pub)
require.NoError(t, err)
p, err := id.PubKey()
require.NoError(t, err)
assert.Equal(t, pub, p)
}
}
t.Run("ECDSA with P256 curve", test(ecdsaP256, did.P256))
t.Run("ECDSA with P384 curve", test(ecdsaP384, did.P384))
t.Run("ECDSA with P521 curve", test(ecdsaP521, did.P521))
t.Run("Ed25519", test(ed25519, did.Ed25519))
t.Run("RSA", test(rsa, did.RSA))
t.Run("secp256k1", test(secp256k1PubKey1, did.Secp256k1))
t.Run("ECDSA with secp256k1 curve (coerced)", func(t *testing.T) {
t.Parallel()
id, err := did.FromPubKey(ecdsaSecp256k1)
require.NoError(t, err)
p, err := id.PubKey()
require.NoError(t, err)
require.Equal(t, pb.KeyType_Secp256k1, p.Type())
})
t.Run("unmarshaled example key (secp256k1)", func(t *testing.T) {
t.Parallel()
id, err := did.FromPubKey(examplePubKey(t))
require.NoError(t, err)
require.Equal(t, exampleDID(t), id)
})
}
func TestToPubKey(t *testing.T) {
t.Parallel()
pubKey, err := did.ToPubKey(exampleDIDStr)
require.NoError(t, err)
require.Equal(t, examplePubKey(t), pubKey)
}
func exampleDID(t *testing.T) did.DID {
t.Helper()
id, err := did.Parse(exampleDIDStr)
require.NoError(t, err)
return id
}
func examplePubKey(t *testing.T) crypto.PubKey {
t.Helper()
pubKeyCfg, err := crypto.ConfigDecodeKey(examplePubKeyStr)
require.NoError(t, err)
pubKey, err := crypto.UnmarshalEd25519PublicKey(pubKeyCfg)
require.NoError(t, err)
return pubKey
}

View File

@@ -1,143 +0,0 @@
package did
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/x509"
"fmt"
"strings"
crypto "github.com/libp2p/go-libp2p/core/crypto"
mbase "github.com/multiformats/go-multibase"
"github.com/multiformats/go-multicodec"
varint "github.com/multiformats/go-varint"
)
// Signature algorithms from the [did:key specification]
//
// [did:key specification]: https://w3c-ccg.github.io/did-method-key/#signature-method-creation-algorithm
const (
X25519 = multicodec.X25519Pub
Ed25519 = multicodec.Ed25519Pub // UCAN required/recommended
P256 = multicodec.P256Pub // UCAN required
P384 = multicodec.P384Pub
P521 = multicodec.P521Pub
Secp256k1 = multicodec.Secp256k1Pub // UCAN required
RSA = multicodec.RsaPub
)
// Undef can be used to represent a nil or undefined DID, using DID{}
// directly is also acceptable.
var Undef = DID{}
// DID is a Decentralized Identifier of the did:key type, directly holding a cryptographic public key.
// [did:key format]: https://w3c-ccg.github.io/did-method-key/
type DID struct {
code multicodec.Code
bytes string // as string instead of []byte to allow the == operator
}
// Parse returns the DID from the string representation or an error if
// the prefix and method are incorrect, if an unknown encryption algorithm
// is specified or if the method-specific-identifier's bytes don't
// represent a public key for the specified encryption algorithm.
func Parse(str string) (DID, error) {
const keyPrefix = "did:key:"
if !strings.HasPrefix(str, keyPrefix) {
return Undef, fmt.Errorf("must start with 'did:key'")
}
baseCodec, bytes, err := mbase.Decode(str[len(keyPrefix):])
if err != nil {
return Undef, err
}
if baseCodec != mbase.Base58BTC {
return Undef, fmt.Errorf("not Base58BTC encoded")
}
code, _, err := varint.FromUvarint(bytes)
if err != nil {
return Undef, err
}
switch multicodec.Code(code) {
case Ed25519, P256, Secp256k1, RSA:
return DID{bytes: string(bytes), code: multicodec.Code(code)}, nil
default:
return Undef, fmt.Errorf("unsupported did:key multicodec: 0x%x", code)
}
}
// MustParse is like Parse but panics instead of returning an error.
func MustParse(str string) DID {
did, err := Parse(str)
if err != nil {
panic(err)
}
return did
}
// Defined tells if the DID is defined, not equal to Undef.
func (d DID) Defined() bool {
return d.code != 0 || len(d.bytes) > 0
}
// PubKey returns the public key encapsulated by the did:key.
func (d DID) PubKey() (crypto.PubKey, error) {
unmarshaler, ok := map[multicodec.Code]crypto.PubKeyUnmarshaller{
X25519: crypto.UnmarshalEd25519PublicKey,
Ed25519: crypto.UnmarshalEd25519PublicKey,
P256: ecdsaPubKeyUnmarshaler(elliptic.P256()),
P384: ecdsaPubKeyUnmarshaler(elliptic.P384()),
P521: ecdsaPubKeyUnmarshaler(elliptic.P521()),
Secp256k1: crypto.UnmarshalSecp256k1PublicKey,
RSA: rsaPubKeyUnmarshaller,
}[d.code]
if !ok {
return nil, fmt.Errorf("unsupported multicodec: %d", d.code)
}
codeSize := varint.UvarintSize(uint64(d.code))
return unmarshaler([]byte(d.bytes)[codeSize:])
}
// String formats the decentralized identity document (DID) as a string.
func (d DID) String() string {
if d == Undef {
return "(undefined)"
}
key, _ := mbase.Encode(mbase.Base58BTC, []byte(d.bytes))
return "did:key:" + key
}
func ecdsaPubKeyUnmarshaler(curve elliptic.Curve) crypto.PubKeyUnmarshaller {
return func(data []byte) (crypto.PubKey, error) {
x, y := elliptic.UnmarshalCompressed(curve, data)
ecdsaPublicKey := &ecdsa.PublicKey{
Curve: curve,
X: x,
Y: y,
}
pkix, err := x509.MarshalPKIXPublicKey(ecdsaPublicKey)
if err != nil {
return nil, err
}
return crypto.UnmarshalECDSAPublicKey(pkix)
}
}
func rsaPubKeyUnmarshaller(data []byte) (crypto.PubKey, error) {
rsaPublicKey, err := x509.ParsePKCS1PublicKey(data)
if err != nil {
return nil, err
}
pkix, err := x509.MarshalPKIXPublicKey(rsaPublicKey)
if err != nil {
return nil, err
}
return crypto.UnmarshalRsaPublicKey(pkix)
}

View File

@@ -1,41 +0,0 @@
package did
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestParseDIDKey(t *testing.T) {
str := "did:key:z6Mkod5Jr3yd5SC7UDueqK4dAAw5xYJYjksy722tA9Boxc4z"
d, err := Parse(str)
require.NoError(t, err)
require.Equal(t, str, d.String())
}
func TestMustParseDIDKey(t *testing.T) {
str := "did:key:z6Mkod5Jr3yd5SC7UDueqK4dAAw5xYJYjksy722tA9Boxc4z"
require.NotPanics(t, func() {
d := MustParse(str)
require.Equal(t, str, d.String())
})
str = "did:key:z7Mkod5Jr3yd5SC7UDueqK4dAAw5xYJYjksy722tA9Boxc4z"
require.Panics(t, func() {
MustParse(str)
})
}
func TestEquivalence(t *testing.T) {
undef0 := DID{}
undef1 := Undef
did0, err := Parse("did:key:z6Mkod5Jr3yd5SC7UDueqK4dAAw5xYJYjksy722tA9Boxc4z")
require.NoError(t, err)
did1, err := Parse("did:key:z6Mkod5Jr3yd5SC7UDueqK4dAAw5xYJYjksy722tA9Boxc4z")
require.NoError(t, err)
require.True(t, undef0 == undef1)
require.False(t, undef0 == did0)
require.True(t, did0 == did1)
require.False(t, undef1 == did1)
}

View File

@@ -1,150 +0,0 @@
// Package didtest provides Personas that can be used for testing. Each
// Persona has a name, crypto.PrivKey and associated crypto.PubKey and
// did.DID.
package didtest
import (
"fmt"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/ucan-wg/go-ucan/did"
)
const (
alicePrivKeyB64 = "CAESQHdNJLBBiuc1AdwPHBkubB2KS1p0cv2JEF7m8tfwtrcm5ajaYPm+XmVCmtcHOF2lGDlmaiDA7emfwD3IrcyES0M="
bobPrivKeyB64 = "CAESQHBz+AIop1g+9iBDj+ufUc/zm9/ry7c6kDFO8Wl/D0+H63V9hC6s9l4npf3pYEFCjBtlR0AMNWMoFQKSlYNKo20="
carolPrivKeyB64 = "CAESQPrCgkcHnYFXDT9AlAydhPECBEivEuuVx9dJxLjVvDTmJIVNivfzg6H4mAiPfYS+5ryVVUZTHZBzvMuvvvG/Ks0="
danPrivKeyB64 = "CAESQCgNhzofKhC+7hW6x+fNd7iMPtQHeEmKRhhlduf/I7/TeOEFYAEflbJ0sAhMeDJ/HQXaAvsWgHEbJ3ZLhP8q2B0="
erinPrivKeyB64 = "CAESQKhCJo5UBpQcthko8DKMFsbdZ+qqQ5oc01CtLCqrE90dF2GfRlrMmot3WPHiHGCmEYi5ZMEHuiSI095e/6O4Bpw="
frankPrivKeyB64 = "CAESQDlXPKsy3jHh7OWTWQqyZF95Ueac5DKo7xD0NOBE5F2BNr1ZVxRmJ2dBELbOt8KP9sOACcO9qlCB7uMA1UQc7sk="
)
// Persona is a generic participant used for cryptographic testing.
type Persona int
// The provided Personas were selected from the first few generic
// participants listed in this [table].
//
// [table]: https://en.wikipedia.org/wiki/Alice_and_Bob#Cryptographic_systems
const (
PersonaAlice Persona = iota + 1
PersonaBob
PersonaCarol
PersonaDan
PersonaErin
PersonaFrank
)
var privKeys map[Persona]crypto.PrivKey
func init() {
privKeys = make(map[Persona]crypto.PrivKey, 6)
for persona, privKeyCfg := range privKeyB64() {
privKeyMar, err := crypto.ConfigDecodeKey(privKeyCfg)
if err != nil {
return
}
privKey, err := crypto.UnmarshalPrivateKey(privKeyMar)
if err != nil {
return
}
privKeys[persona] = privKey
}
}
// DID returns a did.DID based on the Persona's Ed25519 public key.
func (p Persona) DID() did.DID {
d, err := did.FromPrivKey(p.PrivKey())
if err != nil {
panic(err)
}
return d
}
// Name returns the username of the Persona.
func (p Persona) Name() string {
name, ok := map[Persona]string{
PersonaAlice: "Alice",
PersonaBob: "Bob",
PersonaCarol: "Carol",
PersonaDan: "Dan",
PersonaErin: "Erin",
PersonaFrank: "Frank",
}[p]
if !ok {
panic(fmt.Sprintf("Unknown persona: %v", p))
}
return name
}
// PrivKey returns the Ed25519 private key for the Persona.
func (p Persona) PrivKey() crypto.PrivKey {
res, ok := privKeys[p]
if !ok {
panic(fmt.Sprintf("Unknown persona: %v", p))
}
return res
}
func (p Persona) PrivKeyConfig() string {
res, ok := privKeyB64()[p]
if !ok {
panic(fmt.Sprintf("Unknown persona: %v", p))
}
return res
}
// PubKey returns the Ed25519 public key for the Persona.
func (p Persona) PubKey() crypto.PubKey {
return p.PrivKey().GetPublic()
}
// PubKeyConfig returns the marshaled and encoded Ed25519 public key
// for the Persona.
func (p Persona) PubKeyConfig() string {
pubKeyMar, err := crypto.MarshalPublicKey(p.PrivKey().GetPublic())
if err != nil {
panic(err)
}
return crypto.ConfigEncodeKey(pubKeyMar)
}
func privKeyB64() map[Persona]string {
return map[Persona]string{
PersonaAlice: alicePrivKeyB64,
PersonaBob: bobPrivKeyB64,
PersonaCarol: carolPrivKeyB64,
PersonaDan: danPrivKeyB64,
PersonaErin: erinPrivKeyB64,
PersonaFrank: frankPrivKeyB64,
}
}
// Personas returns an (alphabetically) ordered list of the defined
// Persona values.
func Personas() []Persona {
return []Persona{
PersonaAlice,
PersonaBob,
PersonaCarol,
PersonaDan,
PersonaErin,
PersonaFrank,
}
}
// DidToName retrieve the persona's name from its DID.
func DidToName(d did.DID) string {
return map[did.DID]string{
PersonaAlice.DID(): "Alice",
PersonaBob.DID(): "Bob",
PersonaCarol.DID(): "Carol",
PersonaDan.DID(): "Dan",
PersonaErin.DID(): "Erin",
PersonaFrank.DID(): "Frank",
}[d]
}

View File

@@ -1,82 +0,0 @@
//go:build jwx_es256k
package did_test
import (
"encoding/json"
"os"
"path/filepath"
"testing"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/ucan-wg/go-ucan/did"
"github.com/ucan-wg/go-ucan/did/testvectors"
)
// TestDidKeyVectors executes tests read from the [test vector files] provided
// as part of the DID Key method's [specification].
//
// [test vector files]: https://github.com/w3c-ccg/did-method-key/tree/main/test-vectors
// [specification]: https://w3c-ccg.github.io/did-method-key
func TestDidKeyVectors(t *testing.T) {
t.Parallel()
for _, f := range []string{
// TODO: These test vectors are not supported by go-libp2p/core/crypto
// "bls12381.json",
"ed25519-x25519.json",
"nist-curves.json",
"rsa.json",
"secp256k1.json",
// This test vector only contains a DID Document
// "x25519.json",
} {
vectors := loadTestVectors(t, f)
t.Run(f, func(t *testing.T) {
t.Parallel()
for k, vector := range vectors {
t.Run(k, func(t *testing.T) {
// round-trip pubkey-->did-->pubkey, verified against the test vectors.
exp := vectorPubKey(t, vector)
id, err := did.FromPubKey(exp)
require.NoError(t, err, f, k)
act, err := id.PubKey()
require.NoError(t, err)
assert.Equal(t, k, id.String(), f, k)
assert.Equal(t, exp, act)
})
}
})
}
}
func loadTestVectors(t *testing.T, filename string) testvectors.Vectors {
t.Helper()
data, err := os.ReadFile(filepath.Join("testvectors", filename))
require.NoError(t, err)
var vs testvectors.Vectors
require.NoError(t, json.Unmarshal(data, &vs))
return vs
}
func vectorPubKey(t *testing.T, v testvectors.Vector) crypto.PubKey {
t.Helper()
pubKey, err := v.PubKey()
require.NoError(t, err)
require.NotZero(t, pubKey)
return pubKey
}

View File

@@ -1,231 +0,0 @@
{
"did:key:zUC7K4ndUaGZgV7Cp2yJy6JtMoUHY6u7tkcSYUvPrEidqBmLCTLmi6d5WvwnUqejscAkERJ3bfjEiSYtdPkRSE8kSa11hFBr4sTgnbZ95SJj19PN2jdvJjyzpSZgxkyyxNnBNnY": {
"verificationKeyPair": {
"id": "#zUC7K4ndUaGZgV7Cp2yJy6JtMoUHY6u7tkcSYUvPrEidqBmLCTLmi6d5WvwnUqejscAkERJ3bfjEiSYtdPkRSE8kSa11hFBr4sTgnbZ95SJj19PN2jdvJjyzpSZgxkyyxNnBNnY",
"type": "Bls12381G2Key2020",
"controller": "did:key:zUC7K4ndUaGZgV7Cp2yJy6JtMoUHY6u7tkcSYUvPrEidqBmLCTLmi6d5WvwnUqejscAkERJ3bfjEiSYtdPkRSE8kSa11hFBr4sTgnbZ95SJj19PN2jdvJjyzpSZgxkyyxNnBNnY",
"publicKeyBase58": "25EEkQtcLKsEzQ6JTo9cg4W7NHpaurn4Wg6LaNPFq6JQXnrP91SDviUz7KrJVMJd76CtAZFsRLYzvgX2JGxo2ccUHtuHk7ELCWwrkBDfrXCFVfqJKDootee9iVaF6NpdJtBE",
"privateKeyBase58": "8TXrPTbhefHvcz2vkGsDLBZT2UMeemveLKbdh5JZCvvn"
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/bls12381-2020/v1"
],
"id": "did:key:zUC7K4ndUaGZgV7Cp2yJy6JtMoUHY6u7tkcSYUvPrEidqBmLCTLmi6d5WvwnUqejscAkERJ3bfjEiSYtdPkRSE8kSa11hFBr4sTgnbZ95SJj19PN2jdvJjyzpSZgxkyyxNnBNnY",
"verificationMethod": [
{
"id": "did:key:zUC7K4ndUaGZgV7Cp2yJy6JtMoUHY6u7tkcSYUvPrEidqBmLCTLmi6d5WvwnUqejscAkERJ3bfjEiSYtdPkRSE8kSa11hFBr4sTgnbZ95SJj19PN2jdvJjyzpSZgxkyyxNnBNnY#zUC7K4ndUaGZgV7Cp2yJy6JtMoUHY6u7tkcSYUvPrEidqBmLCTLmi6d5WvwnUqejscAkERJ3bfjEiSYtdPkRSE8kSa11hFBr4sTgnbZ95SJj19PN2jdvJjyzpSZgxkyyxNnBNnY",
"type": "Bls12381G2Key2020",
"controller": "did:key:zUC7K4ndUaGZgV7Cp2yJy6JtMoUHY6u7tkcSYUvPrEidqBmLCTLmi6d5WvwnUqejscAkERJ3bfjEiSYtdPkRSE8kSa11hFBr4sTgnbZ95SJj19PN2jdvJjyzpSZgxkyyxNnBNnY",
"publicKeyBase58": "25EEkQtcLKsEzQ6JTo9cg4W7NHpaurn4Wg6LaNPFq6JQXnrP91SDviUz7KrJVMJd76CtAZFsRLYzvgX2JGxo2ccUHtuHk7ELCWwrkBDfrXCFVfqJKDootee9iVaF6NpdJtBE"
}
],
"assertionMethod": [
"did:key:zUC7K4ndUaGZgV7Cp2yJy6JtMoUHY6u7tkcSYUvPrEidqBmLCTLmi6d5WvwnUqejscAkERJ3bfjEiSYtdPkRSE8kSa11hFBr4sTgnbZ95SJj19PN2jdvJjyzpSZgxkyyxNnBNnY#zUC7K4ndUaGZgV7Cp2yJy6JtMoUHY6u7tkcSYUvPrEidqBmLCTLmi6d5WvwnUqejscAkERJ3bfjEiSYtdPkRSE8kSa11hFBr4sTgnbZ95SJj19PN2jdvJjyzpSZgxkyyxNnBNnY"
],
"authentication": [
"did:key:zUC7K4ndUaGZgV7Cp2yJy6JtMoUHY6u7tkcSYUvPrEidqBmLCTLmi6d5WvwnUqejscAkERJ3bfjEiSYtdPkRSE8kSa11hFBr4sTgnbZ95SJj19PN2jdvJjyzpSZgxkyyxNnBNnY#zUC7K4ndUaGZgV7Cp2yJy6JtMoUHY6u7tkcSYUvPrEidqBmLCTLmi6d5WvwnUqejscAkERJ3bfjEiSYtdPkRSE8kSa11hFBr4sTgnbZ95SJj19PN2jdvJjyzpSZgxkyyxNnBNnY"
],
"capabilityInvocation": [
"did:key:zUC7K4ndUaGZgV7Cp2yJy6JtMoUHY6u7tkcSYUvPrEidqBmLCTLmi6d5WvwnUqejscAkERJ3bfjEiSYtdPkRSE8kSa11hFBr4sTgnbZ95SJj19PN2jdvJjyzpSZgxkyyxNnBNnY#zUC7K4ndUaGZgV7Cp2yJy6JtMoUHY6u7tkcSYUvPrEidqBmLCTLmi6d5WvwnUqejscAkERJ3bfjEiSYtdPkRSE8kSa11hFBr4sTgnbZ95SJj19PN2jdvJjyzpSZgxkyyxNnBNnY"
],
"capabilityDelegation": [
"did:key:zUC7K4ndUaGZgV7Cp2yJy6JtMoUHY6u7tkcSYUvPrEidqBmLCTLmi6d5WvwnUqejscAkERJ3bfjEiSYtdPkRSE8kSa11hFBr4sTgnbZ95SJj19PN2jdvJjyzpSZgxkyyxNnBNnY#zUC7K4ndUaGZgV7Cp2yJy6JtMoUHY6u7tkcSYUvPrEidqBmLCTLmi6d5WvwnUqejscAkERJ3bfjEiSYtdPkRSE8kSa11hFBr4sTgnbZ95SJj19PN2jdvJjyzpSZgxkyyxNnBNnY"
]
}
},
"did:key:zUC77uxiMKceQoxciSy1xgk3nvP8c8NZXDnaY1xsXZaU5UmsZdnwStUke8Ca8zAdPX3MQTHEMhDTCgfdGU7UrY4RRdVhqZp8FaAaoaXFEVp2ZAM7oj3P45BuTCfc3t9FEGBAEQY": {
"verificationKeyPair": {
"id": "#zUC77uxiMKceQoxciSy1xgk3nvP8c8NZXDnaY1xsXZaU5UmsZdnwStUke8Ca8zAdPX3MQTHEMhDTCgfdGU7UrY4RRdVhqZp8FaAaoaXFEVp2ZAM7oj3P45BuTCfc3t9FEGBAEQY",
"type": "Bls12381G2Key2020",
"controller": "did:key:zUC77uxiMKceQoxciSy1xgk3nvP8c8NZXDnaY1xsXZaU5UmsZdnwStUke8Ca8zAdPX3MQTHEMhDTCgfdGU7UrY4RRdVhqZp8FaAaoaXFEVp2ZAM7oj3P45BuTCfc3t9FEGBAEQY",
"publicKeyBase58": "t5QqHdxR4C6QJWJAnk3qVd2DMr4MVFEefdP43i7fLbR5A2qJkE5bqgEtyzpNsDViGEsMKHMdpo7fKbPMhGihbfxz3Dv2Hw36XvprLHBA5DDFSphmy91oHQFdahQMei2HjoE",
"privateKeyBase58": "URWBZN9g2ZfKVdAz1L8pvVwEBqCbGBozt4p8Cootb35"
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/bls12381-2020/v1"
],
"id": "did:key:zUC77uxiMKceQoxciSy1xgk3nvP8c8NZXDnaY1xsXZaU5UmsZdnwStUke8Ca8zAdPX3MQTHEMhDTCgfdGU7UrY4RRdVhqZp8FaAaoaXFEVp2ZAM7oj3P45BuTCfc3t9FEGBAEQY",
"verificationMethod": [
{
"id": "did:key:zUC77uxiMKceQoxciSy1xgk3nvP8c8NZXDnaY1xsXZaU5UmsZdnwStUke8Ca8zAdPX3MQTHEMhDTCgfdGU7UrY4RRdVhqZp8FaAaoaXFEVp2ZAM7oj3P45BuTCfc3t9FEGBAEQY#zUC77uxiMKceQoxciSy1xgk3nvP8c8NZXDnaY1xsXZaU5UmsZdnwStUke8Ca8zAdPX3MQTHEMhDTCgfdGU7UrY4RRdVhqZp8FaAaoaXFEVp2ZAM7oj3P45BuTCfc3t9FEGBAEQY",
"type": "Bls12381G2Key2020",
"controller": "did:key:zUC77uxiMKceQoxciSy1xgk3nvP8c8NZXDnaY1xsXZaU5UmsZdnwStUke8Ca8zAdPX3MQTHEMhDTCgfdGU7UrY4RRdVhqZp8FaAaoaXFEVp2ZAM7oj3P45BuTCfc3t9FEGBAEQY",
"publicKeyBase58": "t5QqHdxR4C6QJWJAnk3qVd2DMr4MVFEefdP43i7fLbR5A2qJkE5bqgEtyzpNsDViGEsMKHMdpo7fKbPMhGihbfxz3Dv2Hw36XvprLHBA5DDFSphmy91oHQFdahQMei2HjoE"
}
],
"assertionMethod": [
"did:key:zUC77uxiMKceQoxciSy1xgk3nvP8c8NZXDnaY1xsXZaU5UmsZdnwStUke8Ca8zAdPX3MQTHEMhDTCgfdGU7UrY4RRdVhqZp8FaAaoaXFEVp2ZAM7oj3P45BuTCfc3t9FEGBAEQY#zUC77uxiMKceQoxciSy1xgk3nvP8c8NZXDnaY1xsXZaU5UmsZdnwStUke8Ca8zAdPX3MQTHEMhDTCgfdGU7UrY4RRdVhqZp8FaAaoaXFEVp2ZAM7oj3P45BuTCfc3t9FEGBAEQY"
],
"authentication": [
"did:key:zUC77uxiMKceQoxciSy1xgk3nvP8c8NZXDnaY1xsXZaU5UmsZdnwStUke8Ca8zAdPX3MQTHEMhDTCgfdGU7UrY4RRdVhqZp8FaAaoaXFEVp2ZAM7oj3P45BuTCfc3t9FEGBAEQY#zUC77uxiMKceQoxciSy1xgk3nvP8c8NZXDnaY1xsXZaU5UmsZdnwStUke8Ca8zAdPX3MQTHEMhDTCgfdGU7UrY4RRdVhqZp8FaAaoaXFEVp2ZAM7oj3P45BuTCfc3t9FEGBAEQY"
],
"capabilityInvocation": [
"did:key:zUC77uxiMKceQoxciSy1xgk3nvP8c8NZXDnaY1xsXZaU5UmsZdnwStUke8Ca8zAdPX3MQTHEMhDTCgfdGU7UrY4RRdVhqZp8FaAaoaXFEVp2ZAM7oj3P45BuTCfc3t9FEGBAEQY#zUC77uxiMKceQoxciSy1xgk3nvP8c8NZXDnaY1xsXZaU5UmsZdnwStUke8Ca8zAdPX3MQTHEMhDTCgfdGU7UrY4RRdVhqZp8FaAaoaXFEVp2ZAM7oj3P45BuTCfc3t9FEGBAEQY"
],
"capabilityDelegation": [
"did:key:zUC77uxiMKceQoxciSy1xgk3nvP8c8NZXDnaY1xsXZaU5UmsZdnwStUke8Ca8zAdPX3MQTHEMhDTCgfdGU7UrY4RRdVhqZp8FaAaoaXFEVp2ZAM7oj3P45BuTCfc3t9FEGBAEQY#zUC77uxiMKceQoxciSy1xgk3nvP8c8NZXDnaY1xsXZaU5UmsZdnwStUke8Ca8zAdPX3MQTHEMhDTCgfdGU7UrY4RRdVhqZp8FaAaoaXFEVp2ZAM7oj3P45BuTCfc3t9FEGBAEQY"
]
}
},
"did:key:zUC7KKoJk5ttwuuc8pmQDiUmtckEPTwcaFVZe4DSFV7fURuoRnD17D3xkBK3A9tZqdADkTTMKSwNkhjo9Hs6HfgNUXo48TNRaxU6XPLSPdRgMc15jCD5DfN34ixjoVemY62JxnW": {
"verificationKeyPair": {
"id": "#zUC7KKoJk5ttwuuc8pmQDiUmtckEPTwcaFVZe4DSFV7fURuoRnD17D3xkBK3A9tZqdADkTTMKSwNkhjo9Hs6HfgNUXo48TNRaxU6XPLSPdRgMc15jCD5DfN34ixjoVemY62JxnW",
"type": "Bls12381G2Key2020",
"controller": "did:key:zUC7KKoJk5ttwuuc8pmQDiUmtckEPTwcaFVZe4DSFV7fURuoRnD17D3xkBK3A9tZqdADkTTMKSwNkhjo9Hs6HfgNUXo48TNRaxU6XPLSPdRgMc15jCD5DfN34ixjoVemY62JxnW",
"publicKeyBase58": "25VFRgQEfbJ3Pit6Z3mnZbKPK9BdQYGwdmfdcmderjYZ12BFNQYeowjMN1AYKKKcacF3UH35ZNpBqCR8y8QLeeaGLL7UKdKLcFje3VQnosesDNHsU8jBvtvYmLJusxXsSUBC",
"privateKeyBase58": "48FTGTBBhezV7Ldk5g392NSxP2hwgEgWiSZQkMoNri7E"
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/bls12381-2020/v1"
],
"id": "did:key:zUC7KKoJk5ttwuuc8pmQDiUmtckEPTwcaFVZe4DSFV7fURuoRnD17D3xkBK3A9tZqdADkTTMKSwNkhjo9Hs6HfgNUXo48TNRaxU6XPLSPdRgMc15jCD5DfN34ixjoVemY62JxnW",
"verificationMethod": [
{
"id": "did:key:zUC7KKoJk5ttwuuc8pmQDiUmtckEPTwcaFVZe4DSFV7fURuoRnD17D3xkBK3A9tZqdADkTTMKSwNkhjo9Hs6HfgNUXo48TNRaxU6XPLSPdRgMc15jCD5DfN34ixjoVemY62JxnW#zUC7KKoJk5ttwuuc8pmQDiUmtckEPTwcaFVZe4DSFV7fURuoRnD17D3xkBK3A9tZqdADkTTMKSwNkhjo9Hs6HfgNUXo48TNRaxU6XPLSPdRgMc15jCD5DfN34ixjoVemY62JxnW",
"type": "Bls12381G2Key2020",
"controller": "did:key:zUC7KKoJk5ttwuuc8pmQDiUmtckEPTwcaFVZe4DSFV7fURuoRnD17D3xkBK3A9tZqdADkTTMKSwNkhjo9Hs6HfgNUXo48TNRaxU6XPLSPdRgMc15jCD5DfN34ixjoVemY62JxnW",
"publicKeyBase58": "25VFRgQEfbJ3Pit6Z3mnZbKPK9BdQYGwdmfdcmderjYZ12BFNQYeowjMN1AYKKKcacF3UH35ZNpBqCR8y8QLeeaGLL7UKdKLcFje3VQnosesDNHsU8jBvtvYmLJusxXsSUBC"
}
],
"assertionMethod": [
"did:key:zUC7KKoJk5ttwuuc8pmQDiUmtckEPTwcaFVZe4DSFV7fURuoRnD17D3xkBK3A9tZqdADkTTMKSwNkhjo9Hs6HfgNUXo48TNRaxU6XPLSPdRgMc15jCD5DfN34ixjoVemY62JxnW#zUC7KKoJk5ttwuuc8pmQDiUmtckEPTwcaFVZe4DSFV7fURuoRnD17D3xkBK3A9tZqdADkTTMKSwNkhjo9Hs6HfgNUXo48TNRaxU6XPLSPdRgMc15jCD5DfN34ixjoVemY62JxnW"
],
"authentication": [
"did:key:zUC7KKoJk5ttwuuc8pmQDiUmtckEPTwcaFVZe4DSFV7fURuoRnD17D3xkBK3A9tZqdADkTTMKSwNkhjo9Hs6HfgNUXo48TNRaxU6XPLSPdRgMc15jCD5DfN34ixjoVemY62JxnW#zUC7KKoJk5ttwuuc8pmQDiUmtckEPTwcaFVZe4DSFV7fURuoRnD17D3xkBK3A9tZqdADkTTMKSwNkhjo9Hs6HfgNUXo48TNRaxU6XPLSPdRgMc15jCD5DfN34ixjoVemY62JxnW"
],
"capabilityInvocation": [
"did:key:zUC7KKoJk5ttwuuc8pmQDiUmtckEPTwcaFVZe4DSFV7fURuoRnD17D3xkBK3A9tZqdADkTTMKSwNkhjo9Hs6HfgNUXo48TNRaxU6XPLSPdRgMc15jCD5DfN34ixjoVemY62JxnW#zUC7KKoJk5ttwuuc8pmQDiUmtckEPTwcaFVZe4DSFV7fURuoRnD17D3xkBK3A9tZqdADkTTMKSwNkhjo9Hs6HfgNUXo48TNRaxU6XPLSPdRgMc15jCD5DfN34ixjoVemY62JxnW"
],
"capabilityDelegation": [
"did:key:zUC7KKoJk5ttwuuc8pmQDiUmtckEPTwcaFVZe4DSFV7fURuoRnD17D3xkBK3A9tZqdADkTTMKSwNkhjo9Hs6HfgNUXo48TNRaxU6XPLSPdRgMc15jCD5DfN34ixjoVemY62JxnW#zUC7KKoJk5ttwuuc8pmQDiUmtckEPTwcaFVZe4DSFV7fURuoRnD17D3xkBK3A9tZqdADkTTMKSwNkhjo9Hs6HfgNUXo48TNRaxU6XPLSPdRgMc15jCD5DfN34ixjoVemY62JxnW"
]
}
},
"did:key:zUC7FB43ErjeTPiBLZ8wWT3aBTL7QnJ6AAZh9opgV5dKkw291mC23yTnKQ2pTcSgLbdKnVJ1ARn6XrwxWqvFg5dRFzCjwSg1j35nRgs5c2nbqkJ4auPTyPtkJ3xcABRNWaDX6QU": {
"verificationKeyPair": {
"id": "#zUC7FB43ErjeTPiBLZ8wWT3aBTL7QnJ6AAZh9opgV5dKkw291mC23yTnKQ2pTcSgLbdKnVJ1ARn6XrwxWqvFg5dRFzCjwSg1j35nRgs5c2nbqkJ4auPTyPtkJ3xcABRNWaDX6QU",
"type": "Bls12381G2Key2020",
"controller": "did:key:zUC7FB43ErjeTPiBLZ8wWT3aBTL7QnJ6AAZh9opgV5dKkw291mC23yTnKQ2pTcSgLbdKnVJ1ARn6XrwxWqvFg5dRFzCjwSg1j35nRgs5c2nbqkJ4auPTyPtkJ3xcABRNWaDX6QU",
"publicKeyBase58": "21LWABB5R6mqxvcU6LWMMt9yCAVyt8C1mHREs1EAX23fLcAEPMK4dWx59Jd6RpJ5geGt881vH9yPzZyC8WpHhS2g296mumPxJA3Aghp9jMoACE13rtTie8FYdgzgUw24eboA",
"privateKeyBase58": "86rp8w6Q7zgDdKqYxZsdTyhZogzwbcR7wf3VQrhV3xLG"
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/bls12381-2020/v1"
],
"id": "did:key:zUC7FB43ErjeTPiBLZ8wWT3aBTL7QnJ6AAZh9opgV5dKkw291mC23yTnKQ2pTcSgLbdKnVJ1ARn6XrwxWqvFg5dRFzCjwSg1j35nRgs5c2nbqkJ4auPTyPtkJ3xcABRNWaDX6QU",
"verificationMethod": [
{
"id": "did:key:zUC7FB43ErjeTPiBLZ8wWT3aBTL7QnJ6AAZh9opgV5dKkw291mC23yTnKQ2pTcSgLbdKnVJ1ARn6XrwxWqvFg5dRFzCjwSg1j35nRgs5c2nbqkJ4auPTyPtkJ3xcABRNWaDX6QU#zUC7FB43ErjeTPiBLZ8wWT3aBTL7QnJ6AAZh9opgV5dKkw291mC23yTnKQ2pTcSgLbdKnVJ1ARn6XrwxWqvFg5dRFzCjwSg1j35nRgs5c2nbqkJ4auPTyPtkJ3xcABRNWaDX6QU",
"type": "Bls12381G2Key2020",
"controller": "did:key:zUC7FB43ErjeTPiBLZ8wWT3aBTL7QnJ6AAZh9opgV5dKkw291mC23yTnKQ2pTcSgLbdKnVJ1ARn6XrwxWqvFg5dRFzCjwSg1j35nRgs5c2nbqkJ4auPTyPtkJ3xcABRNWaDX6QU",
"publicKeyBase58": "21LWABB5R6mqxvcU6LWMMt9yCAVyt8C1mHREs1EAX23fLcAEPMK4dWx59Jd6RpJ5geGt881vH9yPzZyC8WpHhS2g296mumPxJA3Aghp9jMoACE13rtTie8FYdgzgUw24eboA"
}
],
"assertionMethod": [
"did:key:zUC7FB43ErjeTPiBLZ8wWT3aBTL7QnJ6AAZh9opgV5dKkw291mC23yTnKQ2pTcSgLbdKnVJ1ARn6XrwxWqvFg5dRFzCjwSg1j35nRgs5c2nbqkJ4auPTyPtkJ3xcABRNWaDX6QU#zUC7FB43ErjeTPiBLZ8wWT3aBTL7QnJ6AAZh9opgV5dKkw291mC23yTnKQ2pTcSgLbdKnVJ1ARn6XrwxWqvFg5dRFzCjwSg1j35nRgs5c2nbqkJ4auPTyPtkJ3xcABRNWaDX6QU"
],
"authentication": [
"did:key:zUC7FB43ErjeTPiBLZ8wWT3aBTL7QnJ6AAZh9opgV5dKkw291mC23yTnKQ2pTcSgLbdKnVJ1ARn6XrwxWqvFg5dRFzCjwSg1j35nRgs5c2nbqkJ4auPTyPtkJ3xcABRNWaDX6QU#zUC7FB43ErjeTPiBLZ8wWT3aBTL7QnJ6AAZh9opgV5dKkw291mC23yTnKQ2pTcSgLbdKnVJ1ARn6XrwxWqvFg5dRFzCjwSg1j35nRgs5c2nbqkJ4auPTyPtkJ3xcABRNWaDX6QU"
],
"capabilityInvocation": [
"did:key:zUC7FB43ErjeTPiBLZ8wWT3aBTL7QnJ6AAZh9opgV5dKkw291mC23yTnKQ2pTcSgLbdKnVJ1ARn6XrwxWqvFg5dRFzCjwSg1j35nRgs5c2nbqkJ4auPTyPtkJ3xcABRNWaDX6QU#zUC7FB43ErjeTPiBLZ8wWT3aBTL7QnJ6AAZh9opgV5dKkw291mC23yTnKQ2pTcSgLbdKnVJ1ARn6XrwxWqvFg5dRFzCjwSg1j35nRgs5c2nbqkJ4auPTyPtkJ3xcABRNWaDX6QU"
],
"capabilityDelegation": [
"did:key:zUC7FB43ErjeTPiBLZ8wWT3aBTL7QnJ6AAZh9opgV5dKkw291mC23yTnKQ2pTcSgLbdKnVJ1ARn6XrwxWqvFg5dRFzCjwSg1j35nRgs5c2nbqkJ4auPTyPtkJ3xcABRNWaDX6QU#zUC7FB43ErjeTPiBLZ8wWT3aBTL7QnJ6AAZh9opgV5dKkw291mC23yTnKQ2pTcSgLbdKnVJ1ARn6XrwxWqvFg5dRFzCjwSg1j35nRgs5c2nbqkJ4auPTyPtkJ3xcABRNWaDX6QU"
]
}
},
"did:key:zUC7FNFB7UinoJ5tqkeEELWLsytHBdHpwQ7wLVFAYRT6vqdr5uC3JPK6BVNNByj4KxvVKXoirT7VuqptSznjRCgvr7Ksuk42zyFw1GJSYNQSKCpjVcrZXoPUbR1P6zHmr97mVdA": {
"verificationKeyPair": {
"id": "#zUC7FNFB7UinoJ5tqkeEELWLsytHBdHpwQ7wLVFAYRT6vqdr5uC3JPK6BVNNByj4KxvVKXoirT7VuqptSznjRCgvr7Ksuk42zyFw1GJSYNQSKCpjVcrZXoPUbR1P6zHmr97mVdA",
"type": "Bls12381G2Key2020",
"controller": "did:key:zUC7FNFB7UinoJ5tqkeEELWLsytHBdHpwQ7wLVFAYRT6vqdr5uC3JPK6BVNNByj4KxvVKXoirT7VuqptSznjRCgvr7Ksuk42zyFw1GJSYNQSKCpjVcrZXoPUbR1P6zHmr97mVdA",
"publicKeyBase58": "21XhJ3o4ZSgDgRoyP4Pp8agXMwLycuRa1U6fM4ZzJBxH3gJEQbiuwP3Qh2zNoofNrBKPqp3FgXxGvW84cFwMD29oA7Q9w3L8Sjcc3e9mZqFgs8iWxSsDNRcbQdoYtGaxu11r",
"privateKeyBase58": "5LjJ3yibKGP4zKbNgqeiQ284g8LJYnbF7ZBve7Ke9qZ5"
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/bls12381-2020/v1"
],
"id": "did:key:zUC7FNFB7UinoJ5tqkeEELWLsytHBdHpwQ7wLVFAYRT6vqdr5uC3JPK6BVNNByj4KxvVKXoirT7VuqptSznjRCgvr7Ksuk42zyFw1GJSYNQSKCpjVcrZXoPUbR1P6zHmr97mVdA",
"verificationMethod": [
{
"id": "did:key:zUC7FNFB7UinoJ5tqkeEELWLsytHBdHpwQ7wLVFAYRT6vqdr5uC3JPK6BVNNByj4KxvVKXoirT7VuqptSznjRCgvr7Ksuk42zyFw1GJSYNQSKCpjVcrZXoPUbR1P6zHmr97mVdA#zUC7FNFB7UinoJ5tqkeEELWLsytHBdHpwQ7wLVFAYRT6vqdr5uC3JPK6BVNNByj4KxvVKXoirT7VuqptSznjRCgvr7Ksuk42zyFw1GJSYNQSKCpjVcrZXoPUbR1P6zHmr97mVdA",
"type": "Bls12381G2Key2020",
"controller": "did:key:zUC7FNFB7UinoJ5tqkeEELWLsytHBdHpwQ7wLVFAYRT6vqdr5uC3JPK6BVNNByj4KxvVKXoirT7VuqptSznjRCgvr7Ksuk42zyFw1GJSYNQSKCpjVcrZXoPUbR1P6zHmr97mVdA",
"publicKeyBase58": "21XhJ3o4ZSgDgRoyP4Pp8agXMwLycuRa1U6fM4ZzJBxH3gJEQbiuwP3Qh2zNoofNrBKPqp3FgXxGvW84cFwMD29oA7Q9w3L8Sjcc3e9mZqFgs8iWxSsDNRcbQdoYtGaxu11r"
}
],
"assertionMethod": [
"did:key:zUC7FNFB7UinoJ5tqkeEELWLsytHBdHpwQ7wLVFAYRT6vqdr5uC3JPK6BVNNByj4KxvVKXoirT7VuqptSznjRCgvr7Ksuk42zyFw1GJSYNQSKCpjVcrZXoPUbR1P6zHmr97mVdA#zUC7FNFB7UinoJ5tqkeEELWLsytHBdHpwQ7wLVFAYRT6vqdr5uC3JPK6BVNNByj4KxvVKXoirT7VuqptSznjRCgvr7Ksuk42zyFw1GJSYNQSKCpjVcrZXoPUbR1P6zHmr97mVdA"
],
"authentication": [
"did:key:zUC7FNFB7UinoJ5tqkeEELWLsytHBdHpwQ7wLVFAYRT6vqdr5uC3JPK6BVNNByj4KxvVKXoirT7VuqptSznjRCgvr7Ksuk42zyFw1GJSYNQSKCpjVcrZXoPUbR1P6zHmr97mVdA#zUC7FNFB7UinoJ5tqkeEELWLsytHBdHpwQ7wLVFAYRT6vqdr5uC3JPK6BVNNByj4KxvVKXoirT7VuqptSznjRCgvr7Ksuk42zyFw1GJSYNQSKCpjVcrZXoPUbR1P6zHmr97mVdA"
],
"capabilityInvocation": [
"did:key:zUC7FNFB7UinoJ5tqkeEELWLsytHBdHpwQ7wLVFAYRT6vqdr5uC3JPK6BVNNByj4KxvVKXoirT7VuqptSznjRCgvr7Ksuk42zyFw1GJSYNQSKCpjVcrZXoPUbR1P6zHmr97mVdA#zUC7FNFB7UinoJ5tqkeEELWLsytHBdHpwQ7wLVFAYRT6vqdr5uC3JPK6BVNNByj4KxvVKXoirT7VuqptSznjRCgvr7Ksuk42zyFw1GJSYNQSKCpjVcrZXoPUbR1P6zHmr97mVdA"
],
"capabilityDelegation": [
"did:key:zUC7FNFB7UinoJ5tqkeEELWLsytHBdHpwQ7wLVFAYRT6vqdr5uC3JPK6BVNNByj4KxvVKXoirT7VuqptSznjRCgvr7Ksuk42zyFw1GJSYNQSKCpjVcrZXoPUbR1P6zHmr97mVdA#zUC7FNFB7UinoJ5tqkeEELWLsytHBdHpwQ7wLVFAYRT6vqdr5uC3JPK6BVNNByj4KxvVKXoirT7VuqptSznjRCgvr7Ksuk42zyFw1GJSYNQSKCpjVcrZXoPUbR1P6zHmr97mVdA"
]
}
},
"did:key:z5TcCmGLu7HrkT5FTnejDTKcH11LPMQLXMPHTRyzY4KdRvqpPLprH7s1ddWFD38cAkZoiDtofUmJVZyEweUTfwjG5H3znk3ir4tzmuDBUSNbNQ7U6jJqj5bkQLKRaQB1bpFJKGLEq3EBwsfPutL5D7p78kFeLNHznqbf5oGpik7ScaDbGLaTLh1Jtadi6VmPNNd44Cojk": {
"verificationKeyPair": {
"id": "did:key:z5TcCmGLu7HrkT5FTnejDTKcH11LPMQLXMPHTRyzY4KdRvqpPLprH7s1ddWFD38cAkZoiDtofUmJVZyEweUTfwjG5H3znk3ir4tzmuDBUSNbNQ7U6jJqj5bkQLKRaQB1bpFJKGLEq3EBwsfPutL5D7p78kFeLNHznqbf5oGpik7ScaDbGLaTLh1Jtadi6VmPNNd44Cojk#z3tEEysHYz5kkgpfDAByfDVgAuvtSFLHSqoMWmmSZBU1LZtN2sDsAS6RVQSevfxv39kyty",
"type": "JsonWebKey2020",
"controller": "did:key:z5TcCmGLu7HrkT5FTnejDTKcH11LPMQLXMPHTRyzY4KdRvqpPLprH7s1ddWFD38cAkZoiDtofUmJVZyEweUTfwjG5H3znk3ir4tzmuDBUSNbNQ7U6jJqj5bkQLKRaQB1bpFJKGLEq3EBwsfPutL5D7p78kFeLNHznqbf5oGpik7ScaDbGLaTLh1Jtadi6VmPNNd44Cojk",
"publicKeyJwk": {
"kty": "EC",
"crv": "BLS12381_G1",
"x": "im0OQGMTkh4YEhAl16hQwUQTcOaRqIqThqtSwksFK7WaH6Qywypmc3VIDyydmYTe"
},
"privateKeyJwk": {
"kty": "EC",
"crv": "BLS12381_G1",
"x": "im0OQGMTkh4YEhAl16hQwUQTcOaRqIqThqtSwksFK7WaH6Qywypmc3VIDyydmYTe",
"d": "S7Z1TuL05WHge8od0_mW8b3sRM747caCffsLwS6JZ-c"
}
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/jws-2020/v1"
],
"id": "did:key:z5TcCmGLu7HrkT5FTnejDTKcH11LPMQLXMPHTRyzY4KdRvqpPLprH7s1ddWFD38cAkZoiDtofUmJVZyEweUTfwjG5H3znk3ir4tzmuDBUSNbNQ7U6jJqj5bkQLKRaQB1bpFJKGLEq3EBwsfPutL5D7p78kFeLNHznqbf5oGpik7ScaDbGLaTLh1Jtadi6VmPNNd44Cojk",
"verificationMethod": [
{
"id": "did:key:z5TcCmGLu7HrkT5FTnejDTKcH11LPMQLXMPHTRyzY4KdRvqpPLprH7s1ddWFD38cAkZoiDtofUmJVZyEweUTfwjG5H3znk3ir4tzmuDBUSNbNQ7U6jJqj5bkQLKRaQB1bpFJKGLEq3EBwsfPutL5D7p78kFeLNHznqbf5oGpik7ScaDbGLaTLh1Jtadi6VmPNNd44Cojk#z3tEEysHYz5kkgpfDAByfDVgAuvtSFLHSqoMWmmSZBU1LZtN2sDsAS6RVQSevfxv39kyty",
"type": "JsonWebKey2020",
"controller": "did:key:z5TcCmGLu7HrkT5FTnejDTKcH11LPMQLXMPHTRyzY4KdRvqpPLprH7s1ddWFD38cAkZoiDtofUmJVZyEweUTfwjG5H3znk3ir4tzmuDBUSNbNQ7U6jJqj5bkQLKRaQB1bpFJKGLEq3EBwsfPutL5D7p78kFeLNHznqbf5oGpik7ScaDbGLaTLh1Jtadi6VmPNNd44Cojk",
"publicKeyJwk": {
"kty": "EC",
"crv": "BLS12381_G1",
"x": "im0OQGMTkh4YEhAl16hQwUQTcOaRqIqThqtSwksFK7WaH6Qywypmc3VIDyydmYTe"
}
}
],
"assertionMethod": [
"did:key:z5TcCmGLu7HrkT5FTnejDTKcH11LPMQLXMPHTRyzY4KdRvqpPLprH7s1ddWFD38cAkZoiDtofUmJVZyEweUTfwjG5H3znk3ir4tzmuDBUSNbNQ7U6jJqj5bkQLKRaQB1bpFJKGLEq3EBwsfPutL5D7p78kFeLNHznqbf5oGpik7ScaDbGLaTLh1Jtadi6VmPNNd44Cojk#z3tEEysHYz5kkgpfDAByfDVgAuvtSFLHSqoMWmmSZBU1LZtN2sDsAS6RVQSevfxv39kyty"
],
"authentication": [
"did:key:z5TcCmGLu7HrkT5FTnejDTKcH11LPMQLXMPHTRyzY4KdRvqpPLprH7s1ddWFD38cAkZoiDtofUmJVZyEweUTfwjG5H3znk3ir4tzmuDBUSNbNQ7U6jJqj5bkQLKRaQB1bpFJKGLEq3EBwsfPutL5D7p78kFeLNHznqbf5oGpik7ScaDbGLaTLh1Jtadi6VmPNNd44Cojk#z3tEEysHYz5kkgpfDAByfDVgAuvtSFLHSqoMWmmSZBU1LZtN2sDsAS6RVQSevfxv39kyty"
],
"capabilityInvocation": [
"did:key:z5TcCmGLu7HrkT5FTnejDTKcH11LPMQLXMPHTRyzY4KdRvqpPLprH7s1ddWFD38cAkZoiDtofUmJVZyEweUTfwjG5H3znk3ir4tzmuDBUSNbNQ7U6jJqj5bkQLKRaQB1bpFJKGLEq3EBwsfPutL5D7p78kFeLNHznqbf5oGpik7ScaDbGLaTLh1Jtadi6VmPNNd44Cojk#z3tEEysHYz5kkgpfDAByfDVgAuvtSFLHSqoMWmmSZBU1LZtN2sDsAS6RVQSevfxv39kyty"
],
"capabilityDelegation": [
"did:key:z5TcCmGLu7HrkT5FTnejDTKcH11LPMQLXMPHTRyzY4KdRvqpPLprH7s1ddWFD38cAkZoiDtofUmJVZyEweUTfwjG5H3znk3ir4tzmuDBUSNbNQ7U6jJqj5bkQLKRaQB1bpFJKGLEq3EBwsfPutL5D7p78kFeLNHznqbf5oGpik7ScaDbGLaTLh1Jtadi6VmPNNd44Cojk#z3tEEysHYz5kkgpfDAByfDVgAuvtSFLHSqoMWmmSZBU1LZtN2sDsAS6RVQSevfxv39kyty"
]
}
}
}

View File

@@ -1,293 +0,0 @@
{
"did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp": {
"seed": "0000000000000000000000000000000000000000000000000000000000000000",
"verificationKeyPair": {
"id": "#z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp",
"type": "Ed25519VerificationKey2018",
"controller": "did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp",
"publicKeyBase58": "4zvwRjXUKGfvwnParsHAS3HuSVzV5cA4McphgmoCtajS"
},
"keyAgreementKeyPair": {
"id": "#z6LShs9GGnqk85isEBzzshkuVWrVKsRp24GnDuHk8QWkARMW",
"type": "X25519KeyAgreementKey2019",
"controller": "did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp",
"publicKeyBase58": "7By6kV2t2d188odEM4ExAve1UithKT6dLva4dwsDT3ak",
"privateKeyBase58": "6QN8DfuN9hjgHgPvLXqgzqYE3jRRGRrmJQZkd5tL8paR"
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/ed25519-2018/v1",
"https://w3id.org/security/suites/x25519-2019/v1"
],
"id": "did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp",
"verificationMethod": [
{
"id": "did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp#z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp",
"type": "Ed25519VerificationKey2018",
"controller": "did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp",
"publicKeyBase58": "4zvwRjXUKGfvwnParsHAS3HuSVzV5cA4McphgmoCtajS"
},
{
"id": "did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp#z6LShs9GGnqk85isEBzzshkuVWrVKsRp24GnDuHk8QWkARMW",
"type": "X25519KeyAgreementKey2019",
"controller": "did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp",
"publicKeyBase58": "7By6kV2t2d188odEM4ExAve1UithKT6dLva4dwsDT3ak"
}
],
"assertionMethod": [
"did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp#z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp"
],
"authentication": [
"did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp#z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp"
],
"capabilityInvocation": [
"did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp#z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp"
],
"capabilityDelegation": [
"did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp#z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp"
],
"keyAgreement": [
"did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp#z6LShs9GGnqk85isEBzzshkuVWrVKsRp24GnDuHk8QWkARMW"
]
}
},
"did:key:z6MkjchhfUsD6mmvni8mCdXHw216Xrm9bQe2mBH1P5RDjVJG": {
"seed": "0000000000000000000000000000000000000000000000000000000000000001",
"verificationKeyPair": {
"id": "#z6MkjchhfUsD6mmvni8mCdXHw216Xrm9bQe2mBH1P5RDjVJG",
"type": "Ed25519VerificationKey2018",
"controller": "did:key:z6MkjchhfUsD6mmvni8mCdXHw216Xrm9bQe2mBH1P5RDjVJG",
"publicKeyBase58": "6ASf5EcmmEHTgDJ4X4ZT5vT6iHVJBXPg5AN5YoTCpGWt"
},
"keyAgreementKeyPair": {
"id": "#z6LSrHyXiPBhUbvPUtyUCdf32sniiMGPTAesgHrtEa4FePtr",
"type": "X25519KeyAgreementKey2019",
"controller": "did:key:z6MkjchhfUsD6mmvni8mCdXHw216Xrm9bQe2mBH1P5RDjVJG",
"publicKeyBase58": "FcoNC5NqP9CePWbhfz95iHaEsCjGkZUioK9Ck7Qiw286",
"privateKeyBase58": "HBTcN2MrXNRj9xF9oi8QqYyuEPv3JLLjQKuEgW9oxVKP"
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/ed25519-2018/v1",
"https://w3id.org/security/suites/x25519-2019/v1"
],
"id": "did:key:z6MkjchhfUsD6mmvni8mCdXHw216Xrm9bQe2mBH1P5RDjVJG",
"verificationMethod": [
{
"id": "did:key:z6MkjchhfUsD6mmvni8mCdXHw216Xrm9bQe2mBH1P5RDjVJG#z6MkjchhfUsD6mmvni8mCdXHw216Xrm9bQe2mBH1P5RDjVJG",
"type": "Ed25519VerificationKey2018",
"controller": "did:key:z6MkjchhfUsD6mmvni8mCdXHw216Xrm9bQe2mBH1P5RDjVJG",
"publicKeyBase58": "6ASf5EcmmEHTgDJ4X4ZT5vT6iHVJBXPg5AN5YoTCpGWt"
},
{
"id": "did:key:z6MkjchhfUsD6mmvni8mCdXHw216Xrm9bQe2mBH1P5RDjVJG#z6LSrHyXiPBhUbvPUtyUCdf32sniiMGPTAesgHrtEa4FePtr",
"type": "X25519KeyAgreementKey2019",
"controller": "did:key:z6MkjchhfUsD6mmvni8mCdXHw216Xrm9bQe2mBH1P5RDjVJG",
"publicKeyBase58": "FcoNC5NqP9CePWbhfz95iHaEsCjGkZUioK9Ck7Qiw286"
}
],
"assertionMethod": [
"did:key:z6MkjchhfUsD6mmvni8mCdXHw216Xrm9bQe2mBH1P5RDjVJG#z6MkjchhfUsD6mmvni8mCdXHw216Xrm9bQe2mBH1P5RDjVJG"
],
"authentication": [
"did:key:z6MkjchhfUsD6mmvni8mCdXHw216Xrm9bQe2mBH1P5RDjVJG#z6MkjchhfUsD6mmvni8mCdXHw216Xrm9bQe2mBH1P5RDjVJG"
],
"capabilityInvocation": [
"did:key:z6MkjchhfUsD6mmvni8mCdXHw216Xrm9bQe2mBH1P5RDjVJG#z6MkjchhfUsD6mmvni8mCdXHw216Xrm9bQe2mBH1P5RDjVJG"
],
"capabilityDelegation": [
"did:key:z6MkjchhfUsD6mmvni8mCdXHw216Xrm9bQe2mBH1P5RDjVJG#z6MkjchhfUsD6mmvni8mCdXHw216Xrm9bQe2mBH1P5RDjVJG"
],
"keyAgreement": [
"did:key:z6MkjchhfUsD6mmvni8mCdXHw216Xrm9bQe2mBH1P5RDjVJG#z6LSrHyXiPBhUbvPUtyUCdf32sniiMGPTAesgHrtEa4FePtr"
]
}
},
"did:key:z6MknGc3ocHs3zdPiJbnaaqDi58NGb4pk1Sp9WxWufuXSdxf": {
"seed": "0000000000000000000000000000000000000000000000000000000000000002",
"verificationKeyPair": {
"id": "#z6MknGc3ocHs3zdPiJbnaaqDi58NGb4pk1Sp9WxWufuXSdxf",
"type": "Ed25519VerificationKey2018",
"controller": "did:key:z6MknGc3ocHs3zdPiJbnaaqDi58NGb4pk1Sp9WxWufuXSdxf",
"publicKeyBase58": "8pM1DN3RiT8vbom5u1sNryaNT1nyL8CTTW3b5PwWXRBH"
},
"keyAgreementKeyPair": {
"id": "#z6LSkkqoZRC34AEpbkhZCqLDcHQVAxuLpQ7kC8XCXMVUfvjE",
"type": "X25519KeyAgreementKey2019",
"controller": "did:key:z6MknGc3ocHs3zdPiJbnaaqDi58NGb4pk1Sp9WxWufuXSdxf",
"publicKeyBase58": "A5fe37PAxhX5WNKngBpGHhC1KpNE7nwbK9oX2tqwxYxU",
"privateKeyBase58": "ACa4PPJ1LnPNq1iwS33V3Akh7WtnC71WkKFZ9ccM6sX2"
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/ed25519-2018/v1",
"https://w3id.org/security/suites/x25519-2019/v1"
],
"id": "did:key:z6MknGc3ocHs3zdPiJbnaaqDi58NGb4pk1Sp9WxWufuXSdxf",
"verificationMethod": [
{
"id": "did:key:z6MknGc3ocHs3zdPiJbnaaqDi58NGb4pk1Sp9WxWufuXSdxf#z6MknGc3ocHs3zdPiJbnaaqDi58NGb4pk1Sp9WxWufuXSdxf",
"type": "Ed25519VerificationKey2018",
"controller": "did:key:z6MknGc3ocHs3zdPiJbnaaqDi58NGb4pk1Sp9WxWufuXSdxf",
"publicKeyBase58": "8pM1DN3RiT8vbom5u1sNryaNT1nyL8CTTW3b5PwWXRBH"
},
{
"id": "did:key:z6MknGc3ocHs3zdPiJbnaaqDi58NGb4pk1Sp9WxWufuXSdxf#z6LSkkqoZRC34AEpbkhZCqLDcHQVAxuLpQ7kC8XCXMVUfvjE",
"type": "X25519KeyAgreementKey2019",
"controller": "did:key:z6MknGc3ocHs3zdPiJbnaaqDi58NGb4pk1Sp9WxWufuXSdxf",
"publicKeyBase58": "A5fe37PAxhX5WNKngBpGHhC1KpNE7nwbK9oX2tqwxYxU"
}
],
"assertionMethod": [
"did:key:z6MknGc3ocHs3zdPiJbnaaqDi58NGb4pk1Sp9WxWufuXSdxf#z6MknGc3ocHs3zdPiJbnaaqDi58NGb4pk1Sp9WxWufuXSdxf"
],
"authentication": [
"did:key:z6MknGc3ocHs3zdPiJbnaaqDi58NGb4pk1Sp9WxWufuXSdxf#z6MknGc3ocHs3zdPiJbnaaqDi58NGb4pk1Sp9WxWufuXSdxf"
],
"capabilityInvocation": [
"did:key:z6MknGc3ocHs3zdPiJbnaaqDi58NGb4pk1Sp9WxWufuXSdxf#z6MknGc3ocHs3zdPiJbnaaqDi58NGb4pk1Sp9WxWufuXSdxf"
],
"capabilityDelegation": [
"did:key:z6MknGc3ocHs3zdPiJbnaaqDi58NGb4pk1Sp9WxWufuXSdxf#z6MknGc3ocHs3zdPiJbnaaqDi58NGb4pk1Sp9WxWufuXSdxf"
],
"keyAgreement": [
"did:key:z6MknGc3ocHs3zdPiJbnaaqDi58NGb4pk1Sp9WxWufuXSdxf#z6LSkkqoZRC34AEpbkhZCqLDcHQVAxuLpQ7kC8XCXMVUfvjE"
]
}
},
"did:key:z6MkvqoYXQfDDJRv8L4wKzxYeuKyVZBfi9Qo6Ro8MiLH3kDQ": {
"seed": "0000000000000000000000000000000000000000000000000000000000000003",
"verificationKeyPair": {
"id": "#z6MkvqoYXQfDDJRv8L4wKzxYeuKyVZBfi9Qo6Ro8MiLH3kDQ",
"type": "Ed25519VerificationKey2018",
"controller": "did:key:z6MkvqoYXQfDDJRv8L4wKzxYeuKyVZBfi9Qo6Ro8MiLH3kDQ",
"publicKeyBase58": "HPYVwAQmskwT1qEEeRzhoomyfyupJGASQQtCXSNG8XS2"
},
"keyAgreementKeyPair": {
"id": "#z6LSiUo6AEDat8Ze4nQzDo67SGuHLLwsUGkxndHGUjsywHow",
"type": "X25519KeyAgreementKey2019",
"controller": "did:key:z6MkvqoYXQfDDJRv8L4wKzxYeuKyVZBfi9Qo6Ro8MiLH3kDQ",
"publicKeyBase58": "7ocvdvQinfqtyQ3Dh9aA7ggoVCQkmfaoueZazHETDv3B",
"privateKeyBase58": "FZrzd1osCnbK6y6MJzMBW1RcVfL524sNKhSbqRwMuwHT"
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/ed25519-2018/v1",
"https://w3id.org/security/suites/x25519-2019/v1"
],
"id": "did:key:z6MkvqoYXQfDDJRv8L4wKzxYeuKyVZBfi9Qo6Ro8MiLH3kDQ",
"verificationMethod": [
{
"id": "did:key:z6MkvqoYXQfDDJRv8L4wKzxYeuKyVZBfi9Qo6Ro8MiLH3kDQ#z6MkvqoYXQfDDJRv8L4wKzxYeuKyVZBfi9Qo6Ro8MiLH3kDQ",
"type": "Ed25519VerificationKey2018",
"controller": "did:key:z6MkvqoYXQfDDJRv8L4wKzxYeuKyVZBfi9Qo6Ro8MiLH3kDQ",
"publicKeyBase58": "HPYVwAQmskwT1qEEeRzhoomyfyupJGASQQtCXSNG8XS2"
},
{
"id": "did:key:z6MkvqoYXQfDDJRv8L4wKzxYeuKyVZBfi9Qo6Ro8MiLH3kDQ#z6LSiUo6AEDat8Ze4nQzDo67SGuHLLwsUGkxndHGUjsywHow",
"type": "X25519KeyAgreementKey2019",
"controller": "did:key:z6MkvqoYXQfDDJRv8L4wKzxYeuKyVZBfi9Qo6Ro8MiLH3kDQ",
"publicKeyBase58": "7ocvdvQinfqtyQ3Dh9aA7ggoVCQkmfaoueZazHETDv3B"
}
],
"assertionMethod": [
"did:key:z6MkvqoYXQfDDJRv8L4wKzxYeuKyVZBfi9Qo6Ro8MiLH3kDQ#z6MkvqoYXQfDDJRv8L4wKzxYeuKyVZBfi9Qo6Ro8MiLH3kDQ"
],
"authentication": [
"did:key:z6MkvqoYXQfDDJRv8L4wKzxYeuKyVZBfi9Qo6Ro8MiLH3kDQ#z6MkvqoYXQfDDJRv8L4wKzxYeuKyVZBfi9Qo6Ro8MiLH3kDQ"
],
"capabilityInvocation": [
"did:key:z6MkvqoYXQfDDJRv8L4wKzxYeuKyVZBfi9Qo6Ro8MiLH3kDQ#z6MkvqoYXQfDDJRv8L4wKzxYeuKyVZBfi9Qo6Ro8MiLH3kDQ"
],
"capabilityDelegation": [
"did:key:z6MkvqoYXQfDDJRv8L4wKzxYeuKyVZBfi9Qo6Ro8MiLH3kDQ#z6MkvqoYXQfDDJRv8L4wKzxYeuKyVZBfi9Qo6Ro8MiLH3kDQ"
],
"keyAgreement": [
"did:key:z6MkvqoYXQfDDJRv8L4wKzxYeuKyVZBfi9Qo6Ro8MiLH3kDQ#z6LSiUo6AEDat8Ze4nQzDo67SGuHLLwsUGkxndHGUjsywHow"
]
}
},
"did:key:z6MkwYMhwTvsq376YBAcJHy3vyRWzBgn5vKfVqqDCgm7XVKU": {
"seed": "0000000000000000000000000000000000000000000000000000000000000005",
"verificationKeyPair": {
"id": "did:key:z6MkwYMhwTvsq376YBAcJHy3vyRWzBgn5vKfVqqDCgm7XVKU#z6MkwYMhwTvsq376YBAcJHy3vyRWzBgn5vKfVqqDCgm7XVKU",
"type": "JsonWebKey2020",
"controller": "did:key:z6MkwYMhwTvsq376YBAcJHy3vyRWzBgn5vKfVqqDCgm7XVKU",
"publicKeyJwk": {
"kty": "OKP",
"crv": "Ed25519",
"x": "_eT7oDCtAC98L31MMx9J0T-w7HR-zuvsY08f9MvKne8"
},
"privateKeyJwk": {
"kty": "OKP",
"crv": "Ed25519",
"x": "_eT7oDCtAC98L31MMx9J0T-w7HR-zuvsY08f9MvKne8",
"d": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU"
}
},
"keyAgreementKeyPair": {
"id": "did:key:z6MkwYMhwTvsq376YBAcJHy3vyRWzBgn5vKfVqqDCgm7XVKU#z6LSmArkPSdTKjEESsExHRrSwUzYUHgDuWDewXc4nocasvFU",
"type": "JsonWebKey2020",
"controller": "did:key:z6MkwYMhwTvsq376YBAcJHy3vyRWzBgn5vKfVqqDCgm7XVKU",
"publicKeyJwk": {
"kty": "OKP",
"crv": "X25519",
"x": "jRIz3oriXDNZmnb35XQb7K1UIlz3ae1ao1YSqLeBXHs"
},
"privateKeyJwk": {
"kty": "OKP",
"crv": "X25519",
"x": "jRIz3oriXDNZmnb35XQb7K1UIlz3ae1ao1YSqLeBXHs",
"d": "aEAAB3VBFPCQtgF3N__wRiXhMOgeiRGstpPC3gnJ1Eo"
}
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/jws-2020/v1"
],
"id": "did:key:z6MkwYMhwTvsq376YBAcJHy3vyRWzBgn5vKfVqqDCgm7XVKU",
"verificationMethod": [
{
"id": "did:key:z6MkwYMhwTvsq376YBAcJHy3vyRWzBgn5vKfVqqDCgm7XVKU#z6MkwYMhwTvsq376YBAcJHy3vyRWzBgn5vKfVqqDCgm7XVKU",
"type": "JsonWebKey2020",
"controller": "did:key:z6MkwYMhwTvsq376YBAcJHy3vyRWzBgn5vKfVqqDCgm7XVKU",
"publicKeyJwk": {
"kty": "OKP",
"crv": "Ed25519",
"x": "_eT7oDCtAC98L31MMx9J0T-w7HR-zuvsY08f9MvKne8"
}
},
{
"id": "did:key:z6MkwYMhwTvsq376YBAcJHy3vyRWzBgn5vKfVqqDCgm7XVKU#z6LSmArkPSdTKjEESsExHRrSwUzYUHgDuWDewXc4nocasvFU",
"type": "JsonWebKey2020",
"controller": "did:key:z6MkwYMhwTvsq376YBAcJHy3vyRWzBgn5vKfVqqDCgm7XVKU",
"publicKeyJwk": {
"kty": "OKP",
"crv": "X25519",
"x": "jRIz3oriXDNZmnb35XQb7K1UIlz3ae1ao1YSqLeBXHs"
}
}
],
"assertionMethod": [
"did:key:z6MkwYMhwTvsq376YBAcJHy3vyRWzBgn5vKfVqqDCgm7XVKU#z6MkwYMhwTvsq376YBAcJHy3vyRWzBgn5vKfVqqDCgm7XVKU"
],
"authentication": [
"did:key:z6MkwYMhwTvsq376YBAcJHy3vyRWzBgn5vKfVqqDCgm7XVKU#z6MkwYMhwTvsq376YBAcJHy3vyRWzBgn5vKfVqqDCgm7XVKU"
],
"capabilityInvocation": [
"did:key:z6MkwYMhwTvsq376YBAcJHy3vyRWzBgn5vKfVqqDCgm7XVKU#z6MkwYMhwTvsq376YBAcJHy3vyRWzBgn5vKfVqqDCgm7XVKU"
],
"capabilityDelegation": [
"did:key:z6MkwYMhwTvsq376YBAcJHy3vyRWzBgn5vKfVqqDCgm7XVKU#z6MkwYMhwTvsq376YBAcJHy3vyRWzBgn5vKfVqqDCgm7XVKU"
],
"keyAgreement": [
"did:key:z6MkwYMhwTvsq376YBAcJHy3vyRWzBgn5vKfVqqDCgm7XVKU#z6LSmArkPSdTKjEESsExHRrSwUzYUHgDuWDewXc4nocasvFU"
]
}
}
}

View File

@@ -1,371 +0,0 @@
{
"did:key:zDnaerx9CtbPJ1q36T5Ln5wYt3MQYeGRG5ehnPAmxcf5mDZpv": {
"verificationMethod": {
"id": "#zDnaerx9CtbPJ1q36T5Ln5wYt3MQYeGRG5ehnPAmxcf5mDZpv",
"type": "JsonWebKey2020",
"controller": "did:key:zDnaerx9CtbPJ1q36T5Ln5wYt3MQYeGRG5ehnPAmxcf5mDZpv",
"publicKeyJwk": {
"kty": "EC",
"crv": "P-256",
"x": "igrFmi0whuihKnj9R3Om1SoMph72wUGeFaBbzG2vzns",
"y": "efsX5b10x8yjyrj4ny3pGfLcY7Xby1KzgqOdqnsrJIM"
},
"privateKeyJwk": {
"kty": "EC",
"crv": "P-256",
"x": "igrFmi0whuihKnj9R3Om1SoMph72wUGeFaBbzG2vzns",
"y": "efsX5b10x8yjyrj4ny3pGfLcY7Xby1KzgqOdqnsrJIM",
"d": "gPh-VvVS8MbvKQ9LSVVmfnxnKjHn4Tqj0bmbpehRlpc"
}
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/jws-2020/v1"
],
"id": "did:key:zDnaerx9CtbPJ1q36T5Ln5wYt3MQYeGRG5ehnPAmxcf5mDZpv",
"verificationMethod": [
{
"id": "did:key:zDnaerx9CtbPJ1q36T5Ln5wYt3MQYeGRG5ehnPAmxcf5mDZpv#zDnaerx9CtbPJ1q36T5Ln5wYt3MQYeGRG5ehnPAmxcf5mDZpv",
"type": "JsonWebKey2020",
"controller": "did:key:zDnaerx9CtbPJ1q36T5Ln5wYt3MQYeGRG5ehnPAmxcf5mDZpv",
"publicKeyJwk": {
"kty": "EC",
"crv": "P-256",
"x": "igrFmi0whuihKnj9R3Om1SoMph72wUGeFaBbzG2vzns",
"y": "efsX5b10x8yjyrj4ny3pGfLcY7Xby1KzgqOdqnsrJIM"
}
}
],
"assertionMethod": [
"did:key:zDnaerx9CtbPJ1q36T5Ln5wYt3MQYeGRG5ehnPAmxcf5mDZpv#zDnaerx9CtbPJ1q36T5Ln5wYt3MQYeGRG5ehnPAmxcf5mDZpv"
],
"authentication": [
"did:key:zDnaerx9CtbPJ1q36T5Ln5wYt3MQYeGRG5ehnPAmxcf5mDZpv#zDnaerx9CtbPJ1q36T5Ln5wYt3MQYeGRG5ehnPAmxcf5mDZpv"
],
"capabilityInvocation": [
"did:key:zDnaerx9CtbPJ1q36T5Ln5wYt3MQYeGRG5ehnPAmxcf5mDZpv#zDnaerx9CtbPJ1q36T5Ln5wYt3MQYeGRG5ehnPAmxcf5mDZpv"
],
"capabilityDelegation": [
"did:key:zDnaerx9CtbPJ1q36T5Ln5wYt3MQYeGRG5ehnPAmxcf5mDZpv#zDnaerx9CtbPJ1q36T5Ln5wYt3MQYeGRG5ehnPAmxcf5mDZpv"
],
"keyAgreement": [
"did:key:zDnaerx9CtbPJ1q36T5Ln5wYt3MQYeGRG5ehnPAmxcf5mDZpv#zDnaerx9CtbPJ1q36T5Ln5wYt3MQYeGRG5ehnPAmxcf5mDZpv"
]
}
},
"did:key:zDnaerDaTF5BXEavCrfRZEk316dpbLsfPDZ3WJ5hRTPFU2169": {
"verificationMethod": {
"id": "#zDnaerDaTF5BXEavCrfRZEk316dpbLsfPDZ3WJ5hRTPFU2169",
"type": "JsonWebKey2020",
"controller": "did:key:zDnaerDaTF5BXEavCrfRZEk316dpbLsfPDZ3WJ5hRTPFU2169",
"publicKeyJwk": {
"kty": "EC",
"crv": "P-256",
"x": "fyNYMN0976ci7xqiSdag3buk-ZCwgXU4kz9XNkBlNUI",
"y": "hW2ojTNfH7Jbi8--CJUo3OCbH3y5n91g-IMA9MLMbTU"
},
"privateKeyJwk": {
"kty": "EC",
"crv": "P-256",
"x": "fyNYMN0976ci7xqiSdag3buk-ZCwgXU4kz9XNkBlNUI",
"y": "hW2ojTNfH7Jbi8--CJUo3OCbH3y5n91g-IMA9MLMbTU",
"d": "YjRs6vNvw4sYrzVVY8ipkEpDAD9PFqw1sUnvPRMA-WI"
}
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/jws-2020/v1"
],
"id": "did:key:zDnaerDaTF5BXEavCrfRZEk316dpbLsfPDZ3WJ5hRTPFU2169",
"verificationMethod": [
{
"id": "did:key:zDnaerDaTF5BXEavCrfRZEk316dpbLsfPDZ3WJ5hRTPFU2169#zDnaerDaTF5BXEavCrfRZEk316dpbLsfPDZ3WJ5hRTPFU2169",
"type": "JsonWebKey2020",
"controller": "did:key:zDnaerDaTF5BXEavCrfRZEk316dpbLsfPDZ3WJ5hRTPFU2169",
"publicKeyJwk": {
"kty": "EC",
"crv": "P-256",
"x": "fyNYMN0976ci7xqiSdag3buk-ZCwgXU4kz9XNkBlNUI",
"y": "hW2ojTNfH7Jbi8--CJUo3OCbH3y5n91g-IMA9MLMbTU"
}
}
],
"assertionMethod": [
"did:key:zDnaerDaTF5BXEavCrfRZEk316dpbLsfPDZ3WJ5hRTPFU2169#zDnaerDaTF5BXEavCrfRZEk316dpbLsfPDZ3WJ5hRTPFU2169"
],
"authentication": [
"did:key:zDnaerDaTF5BXEavCrfRZEk316dpbLsfPDZ3WJ5hRTPFU2169#zDnaerDaTF5BXEavCrfRZEk316dpbLsfPDZ3WJ5hRTPFU2169"
],
"capabilityInvocation": [
"did:key:zDnaerDaTF5BXEavCrfRZEk316dpbLsfPDZ3WJ5hRTPFU2169#zDnaerDaTF5BXEavCrfRZEk316dpbLsfPDZ3WJ5hRTPFU2169"
],
"capabilityDelegation": [
"did:key:zDnaerDaTF5BXEavCrfRZEk316dpbLsfPDZ3WJ5hRTPFU2169#zDnaerDaTF5BXEavCrfRZEk316dpbLsfPDZ3WJ5hRTPFU2169"
],
"keyAgreement": [
"did:key:zDnaerDaTF5BXEavCrfRZEk316dpbLsfPDZ3WJ5hRTPFU2169#zDnaerDaTF5BXEavCrfRZEk316dpbLsfPDZ3WJ5hRTPFU2169"
]
}
},
"did:key:z82Lm1MpAkeJcix9K8TMiLd5NMAhnwkjjCBeWHXyu3U4oT2MVJJKXkcVBgjGhnLBn2Kaau9": {
"verificationMethod": {
"id": "#z82Lm1MpAkeJcix9K8TMiLd5NMAhnwkjjCBeWHXyu3U4oT2MVJJKXkcVBgjGhnLBn2Kaau9",
"type": "JsonWebKey2020",
"controller": "did:key:z82Lm1MpAkeJcix9K8TMiLd5NMAhnwkjjCBeWHXyu3U4oT2MVJJKXkcVBgjGhnLBn2Kaau9",
"publicKeyJwk": {
"kty": "EC",
"crv": "P-384",
"x": "lInTxl8fjLKp_UCrxI0WDklahi-7-_6JbtiHjiRvMvhedhKVdHBfi2HCY8t_QJyc",
"y": "y6N1IC-2mXxHreETBW7K3mBcw0qGr3CWHCs-yl09yCQRLcyfGv7XhqAngHOu51Zv"
},
"privateKeyJwk": {
"kty": "EC",
"crv": "P-384",
"x": "lInTxl8fjLKp_UCrxI0WDklahi-7-_6JbtiHjiRvMvhedhKVdHBfi2HCY8t_QJyc",
"y": "y6N1IC-2mXxHreETBW7K3mBcw0qGr3CWHCs-yl09yCQRLcyfGv7XhqAngHOu51Zv",
"d": "hAyGZNj9031guBCdpAOaZkO-E5m-LKLYnMIq0-msrp8JLctseaOeNTHmP3uKVWwX"
}
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/jws-2020/v1"
],
"id": "did:key:z82Lm1MpAkeJcix9K8TMiLd5NMAhnwkjjCBeWHXyu3U4oT2MVJJKXkcVBgjGhnLBn2Kaau9",
"verificationMethod": [
{
"id": "did:key:z82Lm1MpAkeJcix9K8TMiLd5NMAhnwkjjCBeWHXyu3U4oT2MVJJKXkcVBgjGhnLBn2Kaau9#z82Lm1MpAkeJcix9K8TMiLd5NMAhnwkjjCBeWHXyu3U4oT2MVJJKXkcVBgjGhnLBn2Kaau9",
"type": "JsonWebKey2020",
"controller": "did:key:z82Lm1MpAkeJcix9K8TMiLd5NMAhnwkjjCBeWHXyu3U4oT2MVJJKXkcVBgjGhnLBn2Kaau9",
"publicKeyJwk": {
"kty": "EC",
"crv": "P-384",
"x": "lInTxl8fjLKp_UCrxI0WDklahi-7-_6JbtiHjiRvMvhedhKVdHBfi2HCY8t_QJyc",
"y": "y6N1IC-2mXxHreETBW7K3mBcw0qGr3CWHCs-yl09yCQRLcyfGv7XhqAngHOu51Zv"
}
}
],
"assertionMethod": [
"did:key:z82Lm1MpAkeJcix9K8TMiLd5NMAhnwkjjCBeWHXyu3U4oT2MVJJKXkcVBgjGhnLBn2Kaau9#z82Lm1MpAkeJcix9K8TMiLd5NMAhnwkjjCBeWHXyu3U4oT2MVJJKXkcVBgjGhnLBn2Kaau9"
],
"authentication": [
"did:key:z82Lm1MpAkeJcix9K8TMiLd5NMAhnwkjjCBeWHXyu3U4oT2MVJJKXkcVBgjGhnLBn2Kaau9#z82Lm1MpAkeJcix9K8TMiLd5NMAhnwkjjCBeWHXyu3U4oT2MVJJKXkcVBgjGhnLBn2Kaau9"
],
"capabilityInvocation": [
"did:key:z82Lm1MpAkeJcix9K8TMiLd5NMAhnwkjjCBeWHXyu3U4oT2MVJJKXkcVBgjGhnLBn2Kaau9#z82Lm1MpAkeJcix9K8TMiLd5NMAhnwkjjCBeWHXyu3U4oT2MVJJKXkcVBgjGhnLBn2Kaau9"
],
"capabilityDelegation": [
"did:key:z82Lm1MpAkeJcix9K8TMiLd5NMAhnwkjjCBeWHXyu3U4oT2MVJJKXkcVBgjGhnLBn2Kaau9#z82Lm1MpAkeJcix9K8TMiLd5NMAhnwkjjCBeWHXyu3U4oT2MVJJKXkcVBgjGhnLBn2Kaau9"
],
"keyAgreement": [
"did:key:z82Lm1MpAkeJcix9K8TMiLd5NMAhnwkjjCBeWHXyu3U4oT2MVJJKXkcVBgjGhnLBn2Kaau9#z82Lm1MpAkeJcix9K8TMiLd5NMAhnwkjjCBeWHXyu3U4oT2MVJJKXkcVBgjGhnLBn2Kaau9"
]
}
},
"did:key:z82LkvCwHNreneWpsgPEbV3gu1C6NFJEBg4srfJ5gdxEsMGRJUz2sG9FE42shbn2xkZJh54": {
"verificationMethod": {
"id": "#z82LkvCwHNreneWpsgPEbV3gu1C6NFJEBg4srfJ5gdxEsMGRJUz2sG9FE42shbn2xkZJh54",
"type": "JsonWebKey2020",
"controller": "did:key:z82LkvCwHNreneWpsgPEbV3gu1C6NFJEBg4srfJ5gdxEsMGRJUz2sG9FE42shbn2xkZJh54",
"publicKeyJwk": {
"kty": "EC",
"crv": "P-384",
"x": "CA-iNoHDg1lL8pvX3d1uvExzVfCz7Rn6tW781Ub8K5MrDf2IMPyL0RTDiaLHC1JT",
"y": "Kpnrn8DkXUD3ge4mFxi-DKr0DYO2KuJdwNBrhzLRtfMa3WFMZBiPKUPfJj8dYNl_"
},
"privateKeyJwk": {
"kty": "EC",
"crv": "P-384",
"x": "CA-iNoHDg1lL8pvX3d1uvExzVfCz7Rn6tW781Ub8K5MrDf2IMPyL0RTDiaLHC1JT",
"y": "Kpnrn8DkXUD3ge4mFxi-DKr0DYO2KuJdwNBrhzLRtfMa3WFMZBiPKUPfJj8dYNl_",
"d": "Xe1HHeh-UsrJPRNLR_Y06VTrWpZYBXi7a7kiRqCgwnAOlJZPwE-xzL3DIIVMavAL"
}
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/jws-2020/v1"
],
"id": "did:key:z82LkvCwHNreneWpsgPEbV3gu1C6NFJEBg4srfJ5gdxEsMGRJUz2sG9FE42shbn2xkZJh54",
"verificationMethod": [
{
"id": "did:key:z82LkvCwHNreneWpsgPEbV3gu1C6NFJEBg4srfJ5gdxEsMGRJUz2sG9FE42shbn2xkZJh54#z82LkvCwHNreneWpsgPEbV3gu1C6NFJEBg4srfJ5gdxEsMGRJUz2sG9FE42shbn2xkZJh54",
"type": "JsonWebKey2020",
"controller": "did:key:z82LkvCwHNreneWpsgPEbV3gu1C6NFJEBg4srfJ5gdxEsMGRJUz2sG9FE42shbn2xkZJh54",
"publicKeyJwk": {
"kty": "EC",
"crv": "P-384",
"x": "CA-iNoHDg1lL8pvX3d1uvExzVfCz7Rn6tW781Ub8K5MrDf2IMPyL0RTDiaLHC1JT",
"y": "Kpnrn8DkXUD3ge4mFxi-DKr0DYO2KuJdwNBrhzLRtfMa3WFMZBiPKUPfJj8dYNl_"
}
}
],
"assertionMethod": [
"did:key:z82LkvCwHNreneWpsgPEbV3gu1C6NFJEBg4srfJ5gdxEsMGRJUz2sG9FE42shbn2xkZJh54#z82LkvCwHNreneWpsgPEbV3gu1C6NFJEBg4srfJ5gdxEsMGRJUz2sG9FE42shbn2xkZJh54"
],
"authentication": [
"did:key:z82LkvCwHNreneWpsgPEbV3gu1C6NFJEBg4srfJ5gdxEsMGRJUz2sG9FE42shbn2xkZJh54#z82LkvCwHNreneWpsgPEbV3gu1C6NFJEBg4srfJ5gdxEsMGRJUz2sG9FE42shbn2xkZJh54"
],
"capabilityInvocation": [
"did:key:z82LkvCwHNreneWpsgPEbV3gu1C6NFJEBg4srfJ5gdxEsMGRJUz2sG9FE42shbn2xkZJh54#z82LkvCwHNreneWpsgPEbV3gu1C6NFJEBg4srfJ5gdxEsMGRJUz2sG9FE42shbn2xkZJh54"
],
"capabilityDelegation": [
"did:key:z82LkvCwHNreneWpsgPEbV3gu1C6NFJEBg4srfJ5gdxEsMGRJUz2sG9FE42shbn2xkZJh54#z82LkvCwHNreneWpsgPEbV3gu1C6NFJEBg4srfJ5gdxEsMGRJUz2sG9FE42shbn2xkZJh54"
],
"keyAgreement": [
"did:key:z82LkvCwHNreneWpsgPEbV3gu1C6NFJEBg4srfJ5gdxEsMGRJUz2sG9FE42shbn2xkZJh54#z82LkvCwHNreneWpsgPEbV3gu1C6NFJEBg4srfJ5gdxEsMGRJUz2sG9FE42shbn2xkZJh54"
]
}
},
"did:key:z2J9gaYxrKVpdoG9A4gRnmpnRCcxU6agDtFVVBVdn1JedouoZN7SzcyREXXzWgt3gGiwpoHq7K68X4m32D8HgzG8wv3sY5j7": {
"verificationMethod": {
"id": "#z2J9gaYxrKVpdoG9A4gRnmpnRCcxU6agDtFVVBVdn1JedouoZN7SzcyREXXzWgt3gGiwpoHq7K68X4m32D8HgzG8wv3sY5j7",
"type": "JsonWebKey2020",
"controller": "did:key:z2J9gaYxrKVpdoG9A4gRnmpnRCcxU6agDtFVVBVdn1JedouoZN7SzcyREXXzWgt3gGiwpoHq7K68X4m32D8HgzG8wv3sY5j7",
"publicKeyJwk": {
"kty": "EC",
"crv": "P-521",
"x": "ASUHPMyichQ0QbHZ9ofNx_l4y7luncn5feKLo3OpJ2nSbZoC7mffolj5uy7s6KSKXFmnNWxGJ42IOrjZ47qqwqyS",
"y": "AW9ziIC4ZQQVSNmLlp59yYKrjRY0_VqO-GOIYQ9tYpPraBKUloEId6cI_vynCzlZWZtWpgOM3HPhYEgawQ703RjC"
},
"privateKeyJwk": {
"kty": "EC",
"crv": "P-521",
"x": "ASUHPMyichQ0QbHZ9ofNx_l4y7luncn5feKLo3OpJ2nSbZoC7mffolj5uy7s6KSKXFmnNWxGJ42IOrjZ47qqwqyS",
"y": "AW9ziIC4ZQQVSNmLlp59yYKrjRY0_VqO-GOIYQ9tYpPraBKUloEId6cI_vynCzlZWZtWpgOM3HPhYEgawQ703RjC",
"d": "AHwRaNaGs0jkj_pT6PK2aHep7dJK-yxyoL2bIfVRAceq1baxoiFDo3W14c8E2YZn1k5S53r4a11flhQdaB5guJ_X"
}
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/jws-2020/v1"
],
"id": "did:key:z2J9gaYxrKVpdoG9A4gRnmpnRCcxU6agDtFVVBVdn1JedouoZN7SzcyREXXzWgt3gGiwpoHq7K68X4m32D8HgzG8wv3sY5j7",
"verificationMethod": [
{
"id": "did:key:z2J9gaYxrKVpdoG9A4gRnmpnRCcxU6agDtFVVBVdn1JedouoZN7SzcyREXXzWgt3gGiwpoHq7K68X4m32D8HgzG8wv3sY5j7#z2J9gaYxrKVpdoG9A4gRnmpnRCcxU6agDtFVVBVdn1JedouoZN7SzcyREXXzWgt3gGiwpoHq7K68X4m32D8HgzG8wv3sY5j7",
"type": "JsonWebKey2020",
"controller": "did:key:z2J9gaYxrKVpdoG9A4gRnmpnRCcxU6agDtFVVBVdn1JedouoZN7SzcyREXXzWgt3gGiwpoHq7K68X4m32D8HgzG8wv3sY5j7",
"publicKeyJwk": {
"kty": "EC",
"crv": "P-521",
"x": "ASUHPMyichQ0QbHZ9ofNx_l4y7luncn5feKLo3OpJ2nSbZoC7mffolj5uy7s6KSKXFmnNWxGJ42IOrjZ47qqwqyS",
"y": "AW9ziIC4ZQQVSNmLlp59yYKrjRY0_VqO-GOIYQ9tYpPraBKUloEId6cI_vynCzlZWZtWpgOM3HPhYEgawQ703RjC"
}
}
],
"assertionMethod": [
"did:key:z2J9gaYxrKVpdoG9A4gRnmpnRCcxU6agDtFVVBVdn1JedouoZN7SzcyREXXzWgt3gGiwpoHq7K68X4m32D8HgzG8wv3sY5j7#z2J9gaYxrKVpdoG9A4gRnmpnRCcxU6agDtFVVBVdn1JedouoZN7SzcyREXXzWgt3gGiwpoHq7K68X4m32D8HgzG8wv3sY5j7"
],
"authentication": [
"did:key:z2J9gaYxrKVpdoG9A4gRnmpnRCcxU6agDtFVVBVdn1JedouoZN7SzcyREXXzWgt3gGiwpoHq7K68X4m32D8HgzG8wv3sY5j7#z2J9gaYxrKVpdoG9A4gRnmpnRCcxU6agDtFVVBVdn1JedouoZN7SzcyREXXzWgt3gGiwpoHq7K68X4m32D8HgzG8wv3sY5j7"
],
"capabilityInvocation": [
"did:key:z2J9gaYxrKVpdoG9A4gRnmpnRCcxU6agDtFVVBVdn1JedouoZN7SzcyREXXzWgt3gGiwpoHq7K68X4m32D8HgzG8wv3sY5j7#z2J9gaYxrKVpdoG9A4gRnmpnRCcxU6agDtFVVBVdn1JedouoZN7SzcyREXXzWgt3gGiwpoHq7K68X4m32D8HgzG8wv3sY5j7"
],
"capabilityDelegation": [
"did:key:z2J9gaYxrKVpdoG9A4gRnmpnRCcxU6agDtFVVBVdn1JedouoZN7SzcyREXXzWgt3gGiwpoHq7K68X4m32D8HgzG8wv3sY5j7#z2J9gaYxrKVpdoG9A4gRnmpnRCcxU6agDtFVVBVdn1JedouoZN7SzcyREXXzWgt3gGiwpoHq7K68X4m32D8HgzG8wv3sY5j7"
],
"keyAgreement": [
"did:key:z2J9gaYxrKVpdoG9A4gRnmpnRCcxU6agDtFVVBVdn1JedouoZN7SzcyREXXzWgt3gGiwpoHq7K68X4m32D8HgzG8wv3sY5j7#z2J9gaYxrKVpdoG9A4gRnmpnRCcxU6agDtFVVBVdn1JedouoZN7SzcyREXXzWgt3gGiwpoHq7K68X4m32D8HgzG8wv3sY5j7"
]
}
},
"did:key:z2J9gcGdb2nEyMDmzQYv2QZQcM1vXktvy1Pw4MduSWxGabLZ9XESSWLQgbuPhwnXN7zP7HpTzWqrMTzaY5zWe6hpzJ2jnw4f": {
"verificationMethod": {
"id": "#z2J9gcGdb2nEyMDmzQYv2QZQcM1vXktvy1Pw4MduSWxGabLZ9XESSWLQgbuPhwnXN7zP7HpTzWqrMTzaY5zWe6hpzJ2jnw4f",
"type": "JsonWebKey2020",
"controller": "did:key:z2J9gcGdb2nEyMDmzQYv2QZQcM1vXktvy1Pw4MduSWxGabLZ9XESSWLQgbuPhwnXN7zP7HpTzWqrMTzaY5zWe6hpzJ2jnw4f",
"publicKeyJwk": {
"kty": "EC",
"crv": "P-521",
"x": "AQgyFy6EwH3_u_KXPw8aTXTY7WSVytmbuJeFpq4U6LipxtSmBJe_jjRzms9qubnwm_fGoHMQlvQ1vzS2YLusR2V0",
"y": "Ab06MCcgoG7dM2I-VppdLV1k3lDoeHMvyYqHVfP05Ep2O7Zu0Qwd6IVzfZi9K0KMDud22wdnGUpUtFukZo0EeO15"
},
"privateKeyJwk": {
"kty": "EC",
"crv": "P-521",
"x": "AQgyFy6EwH3_u_KXPw8aTXTY7WSVytmbuJeFpq4U6LipxtSmBJe_jjRzms9qubnwm_fGoHMQlvQ1vzS2YLusR2V0",
"y": "Ab06MCcgoG7dM2I-VppdLV1k3lDoeHMvyYqHVfP05Ep2O7Zu0Qwd6IVzfZi9K0KMDud22wdnGUpUtFukZo0EeO15",
"d": "AbheZ-AA58LP4BpopCGCLH8ZoMdkdJaVOS6KK2NNmDCisr5_Ifxl-qcunrkOJ0CSauA4LJyNbCWcy28Bo6zgHTXQ"
}
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/jws-2020/v1"
],
"id": "did:key:z2J9gcGdb2nEyMDmzQYv2QZQcM1vXktvy1Pw4MduSWxGabLZ9XESSWLQgbuPhwnXN7zP7HpTzWqrMTzaY5zWe6hpzJ2jnw4f",
"verificationMethod": [
{
"id": "did:key:z2J9gcGdb2nEyMDmzQYv2QZQcM1vXktvy1Pw4MduSWxGabLZ9XESSWLQgbuPhwnXN7zP7HpTzWqrMTzaY5zWe6hpzJ2jnw4f#z2J9gcGdb2nEyMDmzQYv2QZQcM1vXktvy1Pw4MduSWxGabLZ9XESSWLQgbuPhwnXN7zP7HpTzWqrMTzaY5zWe6hpzJ2jnw4f",
"type": "JsonWebKey2020",
"controller": "did:key:z2J9gcGdb2nEyMDmzQYv2QZQcM1vXktvy1Pw4MduSWxGabLZ9XESSWLQgbuPhwnXN7zP7HpTzWqrMTzaY5zWe6hpzJ2jnw4f",
"publicKeyJwk": {
"kty": "EC",
"crv": "P-521",
"x": "AQgyFy6EwH3_u_KXPw8aTXTY7WSVytmbuJeFpq4U6LipxtSmBJe_jjRzms9qubnwm_fGoHMQlvQ1vzS2YLusR2V0",
"y": "Ab06MCcgoG7dM2I-VppdLV1k3lDoeHMvyYqHVfP05Ep2O7Zu0Qwd6IVzfZi9K0KMDud22wdnGUpUtFukZo0EeO15"
}
}
],
"assertionMethod": [
"did:key:z2J9gcGdb2nEyMDmzQYv2QZQcM1vXktvy1Pw4MduSWxGabLZ9XESSWLQgbuPhwnXN7zP7HpTzWqrMTzaY5zWe6hpzJ2jnw4f#z2J9gcGdb2nEyMDmzQYv2QZQcM1vXktvy1Pw4MduSWxGabLZ9XESSWLQgbuPhwnXN7zP7HpTzWqrMTzaY5zWe6hpzJ2jnw4f"
],
"authentication": [
"did:key:z2J9gcGdb2nEyMDmzQYv2QZQcM1vXktvy1Pw4MduSWxGabLZ9XESSWLQgbuPhwnXN7zP7HpTzWqrMTzaY5zWe6hpzJ2jnw4f#z2J9gcGdb2nEyMDmzQYv2QZQcM1vXktvy1Pw4MduSWxGabLZ9XESSWLQgbuPhwnXN7zP7HpTzWqrMTzaY5zWe6hpzJ2jnw4f"
],
"capabilityInvocation": [
"did:key:z2J9gcGdb2nEyMDmzQYv2QZQcM1vXktvy1Pw4MduSWxGabLZ9XESSWLQgbuPhwnXN7zP7HpTzWqrMTzaY5zWe6hpzJ2jnw4f#z2J9gcGdb2nEyMDmzQYv2QZQcM1vXktvy1Pw4MduSWxGabLZ9XESSWLQgbuPhwnXN7zP7HpTzWqrMTzaY5zWe6hpzJ2jnw4f"
],
"capabilityDelegation": [
"did:key:z2J9gcGdb2nEyMDmzQYv2QZQcM1vXktvy1Pw4MduSWxGabLZ9XESSWLQgbuPhwnXN7zP7HpTzWqrMTzaY5zWe6hpzJ2jnw4f#z2J9gcGdb2nEyMDmzQYv2QZQcM1vXktvy1Pw4MduSWxGabLZ9XESSWLQgbuPhwnXN7zP7HpTzWqrMTzaY5zWe6hpzJ2jnw4f"
],
"keyAgreement": [
"did:key:z2J9gcGdb2nEyMDmzQYv2QZQcM1vXktvy1Pw4MduSWxGabLZ9XESSWLQgbuPhwnXN7zP7HpTzWqrMTzaY5zWe6hpzJ2jnw4f#z2J9gcGdb2nEyMDmzQYv2QZQcM1vXktvy1Pw4MduSWxGabLZ9XESSWLQgbuPhwnXN7zP7HpTzWqrMTzaY5zWe6hpzJ2jnw4f"
]
}
},
"did:key:zDnaeTiq1PdzvZXUaMdezchcMJQpBdH2VN4pgrrEhMCCbmwSb": {
"verificationMethod": {
"id": "did:key:zDnaeTiq1PdzvZXUaMdezchcMJQpBdH2VN4pgrrEhMCCbmwSb#zDnaeTiq1PdzvZXUaMdezchcMJQpBdH2VN4pgrrEhMCCbmwSb",
"type": "P256Key2021",
"controller": "did:key:zDnaeTiq1PdzvZXUaMdezchcMJQpBdH2VN4pgrrEhMCCbmwSb",
"publicKeyBase58": "ekVhkcBFq3w7jULLkBVye6PwaTuMbhJYuzwFnNcgQAPV",
"privateKeyBase58": "9p4VRzdmhsnq869vQjVCTrRry7u4TtfRxhvBFJTGU2Cp"
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/multikey-2021/v1"
],
"id": "did:key:zDnaeTiq1PdzvZXUaMdezchcMJQpBdH2VN4pgrrEhMCCbmwSb",
"verificationMethod": [
{
"id": "did:key:zDnaeTiq1PdzvZXUaMdezchcMJQpBdH2VN4pgrrEhMCCbmwSb#zDnaeTiq1PdzvZXUaMdezchcMJQpBdH2VN4pgrrEhMCCbmwSb",
"type": "P256Key2021",
"controller": "did:key:zDnaeTiq1PdzvZXUaMdezchcMJQpBdH2VN4pgrrEhMCCbmwSb",
"publicKeyBase58": "ekVhkcBFq3w7jULLkBVye6PwaTuMbhJYuzwFnNcgQAPV"
}
],
"assertionMethod": [
"did:key:zDnaeTiq1PdzvZXUaMdezchcMJQpBdH2VN4pgrrEhMCCbmwSb#zDnaeTiq1PdzvZXUaMdezchcMJQpBdH2VN4pgrrEhMCCbmwSb"
],
"authentication": [
"did:key:zDnaeTiq1PdzvZXUaMdezchcMJQpBdH2VN4pgrrEhMCCbmwSb#zDnaeTiq1PdzvZXUaMdezchcMJQpBdH2VN4pgrrEhMCCbmwSb"
],
"capabilityInvocation": [
"did:key:zDnaeTiq1PdzvZXUaMdezchcMJQpBdH2VN4pgrrEhMCCbmwSb#zDnaeTiq1PdzvZXUaMdezchcMJQpBdH2VN4pgrrEhMCCbmwSb"
],
"capabilityDelegation": [
"did:key:zDnaeTiq1PdzvZXUaMdezchcMJQpBdH2VN4pgrrEhMCCbmwSb#zDnaeTiq1PdzvZXUaMdezchcMJQpBdH2VN4pgrrEhMCCbmwSb"
],
"keyAgreement": [
"did:key:zDnaeTiq1PdzvZXUaMdezchcMJQpBdH2VN4pgrrEhMCCbmwSb#zDnaeTiq1PdzvZXUaMdezchcMJQpBdH2VN4pgrrEhMCCbmwSb"
]
}
}
}

View File

@@ -1,106 +0,0 @@
{
"did:key:z4MXj1wBzi9jUstyPMS4jQqB6KdJaiatPkAtVtGc6bQEQEEsKTic4G7Rou3iBf9vPmT5dbkm9qsZsuVNjq8HCuW1w24nhBFGkRE4cd2Uf2tfrB3N7h4mnyPp1BF3ZttHTYv3DLUPi1zMdkULiow3M1GfXkoC6DoxDUm1jmN6GBj22SjVsr6dxezRVQc7aj9TxE7JLbMH1wh5X3kA58H3DFW8rnYMakFGbca5CB2Jf6CnGQZmL7o5uJAdTwXfy2iiiyPxXEGerMhHwhjTA1mKYobyk2CpeEcmvynADfNZ5MBvcCS7m3XkFCMNUYBS9NQ3fze6vMSUPsNa6GVYmKx2x6JrdEjCk3qRMMmyjnjCMfR4pXbRMZa3i": {
"publicKeyJwk": {
"kty": "RSA",
"n": "sbX82NTV6IylxCh7MfV4hlyvaniCajuP97GyOqSvTmoEdBOflFvZ06kR_9D6ctt45Fk6hskfnag2GG69NALVH2o4RCR6tQiLRpKcMRtDYE_thEmfBvDzm_VVkOIYfxu-Ipuo9J_S5XDNDjczx2v-3oDh5-CIHkU46hvFeCvpUS-L8TJSbgX0kjVk_m4eIb9wh63rtmD6Uz_KBtCo5mmR4TEtcLZKYdqMp3wCjN-TlgHiz_4oVXWbHUefCEe8rFnX1iQnpDHU49_SaXQoud1jCaexFn25n-Aa8f8bc5Vm-5SeRwidHa6ErvEhTvf1dz6GoNPp2iRvm-wJ1gxwWJEYPQ",
"e": "AQAB"
},
"privateKeyJwk": {
"kty": "RSA",
"n": "sbX82NTV6IylxCh7MfV4hlyvaniCajuP97GyOqSvTmoEdBOflFvZ06kR_9D6ctt45Fk6hskfnag2GG69NALVH2o4RCR6tQiLRpKcMRtDYE_thEmfBvDzm_VVkOIYfxu-Ipuo9J_S5XDNDjczx2v-3oDh5-CIHkU46hvFeCvpUS-L8TJSbgX0kjVk_m4eIb9wh63rtmD6Uz_KBtCo5mmR4TEtcLZKYdqMp3wCjN-TlgHiz_4oVXWbHUefCEe8rFnX1iQnpDHU49_SaXQoud1jCaexFn25n-Aa8f8bc5Vm-5SeRwidHa6ErvEhTvf1dz6GoNPp2iRvm-wJ1gxwWJEYPQ",
"e": "AQAB",
"d": "Eym3sT4KLwBzo5pl5nY83-hAti92iLQRizkrKe22RbNi9Y1kKOBatdtGaJqFVztZZu5ERGKNuTd5VdsjJeekSbXviVGRtdHNCvgmRZlWA5261AgIUPxMmKW062GmGJbKQvscFfziBgHK6tyDBd8cZavqMFHi-7ilMYF7IsFBcJKM85x_30pnfd4YwhGQIc9hzv238aOwYKg8c-MzYhEVUnL273jaiLVlfZWQ5ca-GXJHmdOb_Y4fE5gpXfPFBseqleXsMp0VuXxCEsN30LIJHYscdPtbzLD3LFbuMJglFbQqYqssqymILGqJ7Tc2mB2LmXevfqRWz5D7A_K1WzvuoQ",
"p": "ANwlk-eVXPQplCmr7VddX8MAlN5YWvfXkbJe2KOhyS7naSlfMyeW6I0z6q6MAI4h8cs9yEzwmN1oEl_6tZ_-NPd1Oda2Hq5jHx0Jq2P5exIMMbzTTHbB-LjMB4c-b1DZLOrL7ZpCS-CcEHvBz4phzHa7gqz2SrNIGozufbjS_tK5",
"q": "AM6nKRFqRgHiUtGc0xJawpXJeokGhJQFfinDlakjkptuRQNv0BOz8fRUxk6zwwYrx-T_Yk-0oAFsD8qWIgiXg8Wf0bdRW0L0dIH4c6ff3mSREXeAT2h3XDaF0F1YKns08WyYWtOuIiYWChyO9sweK7AUuaOJ-6lr6lElzTGHVf-l",
"dp": "AIHFBPK2cRzchaIq3rVpLVHdveNzYexG_nOOxVVvwRANCUiB_b2Qj3Ts7aIGlS0zhTyxJql0Cig5eNtrBjVRvBdC2t1ebaeOdoC_enBsV8fDuG3-gExg-ySz4JwwiZ2252tg2qbb_a5hULYjARwpmkVDMzyR0mbsUfpRe3q_pcbB",
"dq": "Id2bCVOVLXHdiKReor9k7A8cmaAL0gYkasu2lwVRXU9w1-NXAiOXHydVaEhlSXmbRJflkJJVNmZzIAwCf830tko-oAAhKJPPFA2XRoeVdn2fkynf2YrV_cloICP2skI23kkJeW8sAXnTJmL3ZvP6zNxYn8hZCaa5u5qqSdeX7FE",
"qi": "WKIToXXnjl7GDbz7jCNbX9nWYOE5BDNzVmwiVOnyGoTZfwJ_qtgizj7pOapxi6dT9S9mMavmeAi6LAsEe1WUWtaKSNhbNh0PUGGXlXHGlhkS8jI1ot0e-scrHAuACE567YQ4VurpNorPKtZ5UENXIn74DEmt4l5m6902VF3X5Wo"
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/jws-2020/v1"
],
"id": "did:key:z4MXj1wBzi9jUstyPMS4jQqB6KdJaiatPkAtVtGc6bQEQEEsKTic4G7Rou3iBf9vPmT5dbkm9qsZsuVNjq8HCuW1w24nhBFGkRE4cd2Uf2tfrB3N7h4mnyPp1BF3ZttHTYv3DLUPi1zMdkULiow3M1GfXkoC6DoxDUm1jmN6GBj22SjVsr6dxezRVQc7aj9TxE7JLbMH1wh5X3kA58H3DFW8rnYMakFGbca5CB2Jf6CnGQZmL7o5uJAdTwXfy2iiiyPxXEGerMhHwhjTA1mKYobyk2CpeEcmvynADfNZ5MBvcCS7m3XkFCMNUYBS9NQ3fze6vMSUPsNa6GVYmKx2x6JrdEjCk3qRMMmyjnjCMfR4pXbRMZa3i",
"verificationMethod": [
{
"id": "did:key:z4MXj1wBzi9jUstyPMS4jQqB6KdJaiatPkAtVtGc6bQEQEEsKTic4G7Rou3iBf9vPmT5dbkm9qsZsuVNjq8HCuW1w24nhBFGkRE4cd2Uf2tfrB3N7h4mnyPp1BF3ZttHTYv3DLUPi1zMdkULiow3M1GfXkoC6DoxDUm1jmN6GBj22SjVsr6dxezRVQc7aj9TxE7JLbMH1wh5X3kA58H3DFW8rnYMakFGbca5CB2Jf6CnGQZmL7o5uJAdTwXfy2iiiyPxXEGerMhHwhjTA1mKYobyk2CpeEcmvynADfNZ5MBvcCS7m3XkFCMNUYBS9NQ3fze6vMSUPsNa6GVYmKx2x6JrdEjCk3qRMMmyjnjCMfR4pXbRMZa3i#z4MXj1wBzi9jUstyPMS4jQqB6KdJaiatPkAtVtGc6bQEQEEsKTic4G7Rou3iBf9vPmT5dbkm9qsZsuVNjq8HCuW1w24nhBFGkRE4cd2Uf2tfrB3N7h4mnyPp1BF3ZttHTYv3DLUPi1zMdkULiow3M1GfXkoC6DoxDUm1jmN6GBj22SjVsr6dxezRVQc7aj9TxE7JLbMH1wh5X3kA58H3DFW8rnYMakFGbca5CB2Jf6CnGQZmL7o5uJAdTwXfy2iiiyPxXEGerMhHwhjTA1mKYobyk2CpeEcmvynADfNZ5MBvcCS7m3XkFCMNUYBS9NQ3fze6vMSUPsNa6GVYmKx2x6JrdEjCk3qRMMmyjnjCMfR4pXbRMZa3i",
"type": "JsonWebKey2020",
"controller": "did:key:z4MXj1wBzi9jUstyPMS4jQqB6KdJaiatPkAtVtGc6bQEQEEsKTic4G7Rou3iBf9vPmT5dbkm9qsZsuVNjq8HCuW1w24nhBFGkRE4cd2Uf2tfrB3N7h4mnyPp1BF3ZttHTYv3DLUPi1zMdkULiow3M1GfXkoC6DoxDUm1jmN6GBj22SjVsr6dxezRVQc7aj9TxE7JLbMH1wh5X3kA58H3DFW8rnYMakFGbca5CB2Jf6CnGQZmL7o5uJAdTwXfy2iiiyPxXEGerMhHwhjTA1mKYobyk2CpeEcmvynADfNZ5MBvcCS7m3XkFCMNUYBS9NQ3fze6vMSUPsNa6GVYmKx2x6JrdEjCk3qRMMmyjnjCMfR4pXbRMZa3i",
"publicKeyJwk": {
"kty": "RSA",
"n": "sbX82NTV6IylxCh7MfV4hlyvaniCajuP97GyOqSvTmoEdBOflFvZ06kR_9D6ctt45Fk6hskfnag2GG69NALVH2o4RCR6tQiLRpKcMRtDYE_thEmfBvDzm_VVkOIYfxu-Ipuo9J_S5XDNDjczx2v-3oDh5-CIHkU46hvFeCvpUS-L8TJSbgX0kjVk_m4eIb9wh63rtmD6Uz_KBtCo5mmR4TEtcLZKYdqMp3wCjN-TlgHiz_4oVXWbHUefCEe8rFnX1iQnpDHU49_SaXQoud1jCaexFn25n-Aa8f8bc5Vm-5SeRwidHa6ErvEhTvf1dz6GoNPp2iRvm-wJ1gxwWJEYPQ",
"e": "AQAB"
}
}
],
"authentication": [
"did:key:z4MXj1wBzi9jUstyPMS4jQqB6KdJaiatPkAtVtGc6bQEQEEsKTic4G7Rou3iBf9vPmT5dbkm9qsZsuVNjq8HCuW1w24nhBFGkRE4cd2Uf2tfrB3N7h4mnyPp1BF3ZttHTYv3DLUPi1zMdkULiow3M1GfXkoC6DoxDUm1jmN6GBj22SjVsr6dxezRVQc7aj9TxE7JLbMH1wh5X3kA58H3DFW8rnYMakFGbca5CB2Jf6CnGQZmL7o5uJAdTwXfy2iiiyPxXEGerMhHwhjTA1mKYobyk2CpeEcmvynADfNZ5MBvcCS7m3XkFCMNUYBS9NQ3fze6vMSUPsNa6GVYmKx2x6JrdEjCk3qRMMmyjnjCMfR4pXbRMZa3i#z4MXj1wBzi9jUstyPMS4jQqB6KdJaiatPkAtVtGc6bQEQEEsKTic4G7Rou3iBf9vPmT5dbkm9qsZsuVNjq8HCuW1w24nhBFGkRE4cd2Uf2tfrB3N7h4mnyPp1BF3ZttHTYv3DLUPi1zMdkULiow3M1GfXkoC6DoxDUm1jmN6GBj22SjVsr6dxezRVQc7aj9TxE7JLbMH1wh5X3kA58H3DFW8rnYMakFGbca5CB2Jf6CnGQZmL7o5uJAdTwXfy2iiiyPxXEGerMhHwhjTA1mKYobyk2CpeEcmvynADfNZ5MBvcCS7m3XkFCMNUYBS9NQ3fze6vMSUPsNa6GVYmKx2x6JrdEjCk3qRMMmyjnjCMfR4pXbRMZa3i"
],
"assertionMethod": [
"did:key:z4MXj1wBzi9jUstyPMS4jQqB6KdJaiatPkAtVtGc6bQEQEEsKTic4G7Rou3iBf9vPmT5dbkm9qsZsuVNjq8HCuW1w24nhBFGkRE4cd2Uf2tfrB3N7h4mnyPp1BF3ZttHTYv3DLUPi1zMdkULiow3M1GfXkoC6DoxDUm1jmN6GBj22SjVsr6dxezRVQc7aj9TxE7JLbMH1wh5X3kA58H3DFW8rnYMakFGbca5CB2Jf6CnGQZmL7o5uJAdTwXfy2iiiyPxXEGerMhHwhjTA1mKYobyk2CpeEcmvynADfNZ5MBvcCS7m3XkFCMNUYBS9NQ3fze6vMSUPsNa6GVYmKx2x6JrdEjCk3qRMMmyjnjCMfR4pXbRMZa3i#z4MXj1wBzi9jUstyPMS4jQqB6KdJaiatPkAtVtGc6bQEQEEsKTic4G7Rou3iBf9vPmT5dbkm9qsZsuVNjq8HCuW1w24nhBFGkRE4cd2Uf2tfrB3N7h4mnyPp1BF3ZttHTYv3DLUPi1zMdkULiow3M1GfXkoC6DoxDUm1jmN6GBj22SjVsr6dxezRVQc7aj9TxE7JLbMH1wh5X3kA58H3DFW8rnYMakFGbca5CB2Jf6CnGQZmL7o5uJAdTwXfy2iiiyPxXEGerMhHwhjTA1mKYobyk2CpeEcmvynADfNZ5MBvcCS7m3XkFCMNUYBS9NQ3fze6vMSUPsNa6GVYmKx2x6JrdEjCk3qRMMmyjnjCMfR4pXbRMZa3i"
],
"capabilityDelegation": [
"did:key:z4MXj1wBzi9jUstyPMS4jQqB6KdJaiatPkAtVtGc6bQEQEEsKTic4G7Rou3iBf9vPmT5dbkm9qsZsuVNjq8HCuW1w24nhBFGkRE4cd2Uf2tfrB3N7h4mnyPp1BF3ZttHTYv3DLUPi1zMdkULiow3M1GfXkoC6DoxDUm1jmN6GBj22SjVsr6dxezRVQc7aj9TxE7JLbMH1wh5X3kA58H3DFW8rnYMakFGbca5CB2Jf6CnGQZmL7o5uJAdTwXfy2iiiyPxXEGerMhHwhjTA1mKYobyk2CpeEcmvynADfNZ5MBvcCS7m3XkFCMNUYBS9NQ3fze6vMSUPsNa6GVYmKx2x6JrdEjCk3qRMMmyjnjCMfR4pXbRMZa3i#z4MXj1wBzi9jUstyPMS4jQqB6KdJaiatPkAtVtGc6bQEQEEsKTic4G7Rou3iBf9vPmT5dbkm9qsZsuVNjq8HCuW1w24nhBFGkRE4cd2Uf2tfrB3N7h4mnyPp1BF3ZttHTYv3DLUPi1zMdkULiow3M1GfXkoC6DoxDUm1jmN6GBj22SjVsr6dxezRVQc7aj9TxE7JLbMH1wh5X3kA58H3DFW8rnYMakFGbca5CB2Jf6CnGQZmL7o5uJAdTwXfy2iiiyPxXEGerMhHwhjTA1mKYobyk2CpeEcmvynADfNZ5MBvcCS7m3XkFCMNUYBS9NQ3fze6vMSUPsNa6GVYmKx2x6JrdEjCk3qRMMmyjnjCMfR4pXbRMZa3i"
],
"capabilityInvocation": [
"did:key:z4MXj1wBzi9jUstyPMS4jQqB6KdJaiatPkAtVtGc6bQEQEEsKTic4G7Rou3iBf9vPmT5dbkm9qsZsuVNjq8HCuW1w24nhBFGkRE4cd2Uf2tfrB3N7h4mnyPp1BF3ZttHTYv3DLUPi1zMdkULiow3M1GfXkoC6DoxDUm1jmN6GBj22SjVsr6dxezRVQc7aj9TxE7JLbMH1wh5X3kA58H3DFW8rnYMakFGbca5CB2Jf6CnGQZmL7o5uJAdTwXfy2iiiyPxXEGerMhHwhjTA1mKYobyk2CpeEcmvynADfNZ5MBvcCS7m3XkFCMNUYBS9NQ3fze6vMSUPsNa6GVYmKx2x6JrdEjCk3qRMMmyjnjCMfR4pXbRMZa3i#z4MXj1wBzi9jUstyPMS4jQqB6KdJaiatPkAtVtGc6bQEQEEsKTic4G7Rou3iBf9vPmT5dbkm9qsZsuVNjq8HCuW1w24nhBFGkRE4cd2Uf2tfrB3N7h4mnyPp1BF3ZttHTYv3DLUPi1zMdkULiow3M1GfXkoC6DoxDUm1jmN6GBj22SjVsr6dxezRVQc7aj9TxE7JLbMH1wh5X3kA58H3DFW8rnYMakFGbca5CB2Jf6CnGQZmL7o5uJAdTwXfy2iiiyPxXEGerMhHwhjTA1mKYobyk2CpeEcmvynADfNZ5MBvcCS7m3XkFCMNUYBS9NQ3fze6vMSUPsNa6GVYmKx2x6JrdEjCk3qRMMmyjnjCMfR4pXbRMZa3i"
],
"keyAgreement": [
"did:key:z4MXj1wBzi9jUstyPMS4jQqB6KdJaiatPkAtVtGc6bQEQEEsKTic4G7Rou3iBf9vPmT5dbkm9qsZsuVNjq8HCuW1w24nhBFGkRE4cd2Uf2tfrB3N7h4mnyPp1BF3ZttHTYv3DLUPi1zMdkULiow3M1GfXkoC6DoxDUm1jmN6GBj22SjVsr6dxezRVQc7aj9TxE7JLbMH1wh5X3kA58H3DFW8rnYMakFGbca5CB2Jf6CnGQZmL7o5uJAdTwXfy2iiiyPxXEGerMhHwhjTA1mKYobyk2CpeEcmvynADfNZ5MBvcCS7m3XkFCMNUYBS9NQ3fze6vMSUPsNa6GVYmKx2x6JrdEjCk3qRMMmyjnjCMfR4pXbRMZa3i#z4MXj1wBzi9jUstyPMS4jQqB6KdJaiatPkAtVtGc6bQEQEEsKTic4G7Rou3iBf9vPmT5dbkm9qsZsuVNjq8HCuW1w24nhBFGkRE4cd2Uf2tfrB3N7h4mnyPp1BF3ZttHTYv3DLUPi1zMdkULiow3M1GfXkoC6DoxDUm1jmN6GBj22SjVsr6dxezRVQc7aj9TxE7JLbMH1wh5X3kA58H3DFW8rnYMakFGbca5CB2Jf6CnGQZmL7o5uJAdTwXfy2iiiyPxXEGerMhHwhjTA1mKYobyk2CpeEcmvynADfNZ5MBvcCS7m3XkFCMNUYBS9NQ3fze6vMSUPsNa6GVYmKx2x6JrdEjCk3qRMMmyjnjCMfR4pXbRMZa3i"
]
}
},
"did:key:zgghBUVkqmWS8e1ioRVp2WN9Vw6x4NvnE9PGAyQsPqM3fnfPf8EdauiRVfBTcVDyzhqM5FFC7ekAvuV1cJHawtfgB9wDcru1hPDobk3hqyedijhgWmsYfJCmodkiiFnjNWATE7PvqTyoCjcmrc8yMRXmFPnoASyT5beUd4YZxTE9VfgmavcPy3BSouNmASMQ8xUXeiRwjb7xBaVTiDRjkmyPD7NYZdXuS93gFhyDFr5b3XLg7Rfj9nHEqtHDa7NmAX7iwDAbMUFEfiDEf9hrqZmpAYJracAjTTR8Cvn6mnDXMLwayNG8dcsXFodxok2qksYF4D8ffUxMRmyyQVQhhhmdSi4YaMPqTnC1J6HTG9Yfb98yGSVaWi4TApUhLXFow2ZvB6vqckCNhjCRL2R4MDUSk71qzxWHgezKyDeyThJgdxydrn1osqH94oSeA346eipkJvKqYREXBKwgB5VL6WF4qAK6sVZxJp2dQBfCPVZ4EbsBQaJXaVK7cNcWG8tZBFWZ79gG9Cu6C4u8yjBS8Ux6dCcJPUTLtixQu4z2n5dCsVSNdnP1EEs8ZerZo5pBgc68w4Yuf9KL3xVxPnAB1nRCBfs9cMU6oL1EdyHbqrTfnjE8HpY164akBqe92LFVsk8RusaGsVPrMekT8emTq5y8v8CabuZg5rDs3f9NPEtogjyx49wiub1FecM5B7QqEcZSYiKHgF4mfkteT2": {
"publicKeyJwk": {
"kty": "RSA",
"n": "qMCkFFRFWtzUyZeK8mgJdyM6SEQcXC5E6JwCRVDld-jlJs8sXNOE_vliexq34wZRQ4hk53-JPFlvZ_QjRgIxdUxSMiZ3S5hlNVvvRaue6SMakA9ugQhnfXaWORro0UbPuHLms-bg5StDP8-8tIezu9c1H1FjwPcdbV6rAvKhyhnsM10qP3v2CPbdE0q3FOsihoKuTelImtO110E7N6fLn4U3EYbC4OyViqlrP1o_1M-R-tiM1cb4pD7XKJnIs6ryZdfOQSPBJwjNqSdN6Py_tdrFgPDTyacSSdpTVADOM2IMAoYbhV1N5APhnjOHBRFyKkF1HffQKpmXQLBqvUNNjuhmpVKWBtrTdcCKrglFXiw0cKGHKxIirjmiOlB_HYHg5UdosyE3_1Txct2U7-WBB6QXak1UgxCzgKYBDI8UPA0RlkUuHHP_Zg0fVXrXIInHO04MYxUeSps5qqyP6dJBu_v_BDn3zUq6LYFwJ_-xsU7zbrKYB4jaRlHPoCj_eDC-rSA2uQ4KXHBB8_aAqNFC9ukWxc26Ifz9dF968DLuL30bi-ZAa2oUh492Pw1bg89J7i4qTsOOfpQvGyDV7TGhKuUG3Hbumfr2w16S-_3EI2RIyd1nYsflE6ZmCkZQMG_lwDAFXaqfyGKEDouJuja4XH8r4fGWeGTrozIoniXT1HU",
"e": "AQAB"
},
"privateKeyJwk": {
"kty": "RSA",
"n": "qMCkFFRFWtzUyZeK8mgJdyM6SEQcXC5E6JwCRVDld-jlJs8sXNOE_vliexq34wZRQ4hk53-JPFlvZ_QjRgIxdUxSMiZ3S5hlNVvvRaue6SMakA9ugQhnfXaWORro0UbPuHLms-bg5StDP8-8tIezu9c1H1FjwPcdbV6rAvKhyhnsM10qP3v2CPbdE0q3FOsihoKuTelImtO110E7N6fLn4U3EYbC4OyViqlrP1o_1M-R-tiM1cb4pD7XKJnIs6ryZdfOQSPBJwjNqSdN6Py_tdrFgPDTyacSSdpTVADOM2IMAoYbhV1N5APhnjOHBRFyKkF1HffQKpmXQLBqvUNNjuhmpVKWBtrTdcCKrglFXiw0cKGHKxIirjmiOlB_HYHg5UdosyE3_1Txct2U7-WBB6QXak1UgxCzgKYBDI8UPA0RlkUuHHP_Zg0fVXrXIInHO04MYxUeSps5qqyP6dJBu_v_BDn3zUq6LYFwJ_-xsU7zbrKYB4jaRlHPoCj_eDC-rSA2uQ4KXHBB8_aAqNFC9ukWxc26Ifz9dF968DLuL30bi-ZAa2oUh492Pw1bg89J7i4qTsOOfpQvGyDV7TGhKuUG3Hbumfr2w16S-_3EI2RIyd1nYsflE6ZmCkZQMG_lwDAFXaqfyGKEDouJuja4XH8r4fGWeGTrozIoniXT1HU",
"e": "AQAB",
"d": "TMq1H-clVG7PihkjCqJbRFLMj9wmx6_qfauYwPBKK-HYfWujdW5vxBO6Q-jpqy7RxhiISmxYCBVuw_BuKMqQtR8Q_G9StBzaWYjHfn3Vp6Poz4umLqOjbI2NWNks_ybpGbd30oAK8V5ZkO04ozJpkN4i92hzK3mIc5-z1HiTNUPMn6cStab0VCn6em_ylltV774CEcRJ3OLgid7OUspRt_rID3qyreYbOulTu5WXHIGEnZDzrciIlz1dbcVldpUhD0VAP5ZErD2uUP5oztBNcTTn0YBF8CrOALuQVdaz_t_sNS3P0kWeT1eQ0QwDskO5Hw-Aey2tFeWk1bQyLoQ1A0jsw8mDbkO2zrGfJoxmVBkueTK-q64_n1kV7W1aeJFRj4NwEWmwcrs8GSOGOn38fGB_Y3Kci04qvD6L0QZbFkAVzcJracnxbTdHCEX0jsAAPbYC8M_8PyrPJvPC4IAAWTRrSRbysb7r7viRf4A1vTK9VT7uYyxj7Kzx2cU12d9QBXYfdQ2744bUE7HqN-Vh2rHvv2l5v6vzBRoZ5_OhHHVeUYwC9LouE9lSVAObbFM-Qe1SvzbbwN91LziI7UzUc_xMAEiNwt6PpnIAWAhdvSRawEllTwUcn89udHd5UhiAcm-RQOqXIdA9Aly6d8TT8R1p-ZnQ_gbZyBZeS39AuvU=",
"p": "1p4cypsJeTyVXXc5bQpvzVenPy78OHXtGcFQnbTjW8x1GsvJ-rlHAcjUImd44pgNQNe-iYpeUg3KqfONeedNgQCFd8kP7GoVAd45mEvsGBXvjoCXOBMQlsf8UU_hm_LKhVvTvTmMGoudnNv5qYNDMCGJGzwoG-aSvROlIoXzHmDnusZ-hKsDxM9j0PPz21t99Y_Fr30Oq3FIWXPVmLYmfyZYQkxm9a9WNMkqRbwJuMwGI6V9ABsQ1dW_KJzp_aEBbJLcDr9DsWhm9ErLeAlzyaDYEai6wCtKm9em4LDwCbKhJq3hWEp1sIG-hwx1sk7N4i-b8lBijjEQE-dbSQxUlw==",
"q": "yUqMejfrttGujadj7Uf7q91KM7nbQGny4TjD-CqibcFE-s2_DExCgP1wfhUPfJr2uPQDIe4g12uaNoa5GbCSDaQwEmQpurC_5mazt-z-_tbI24hoPQm5Hq67fZz-jDE_3OccLPLIWtajJqmxHbbB5VqskMuXo8KDxPRfBQBhykmb9_5M8pY2ggZOV4shCUn5E9nOnvibvw5Wx4CBtWUtca4rhpd3mVen1d8xCe4xTG_ni_w1lwdxzU1GmRFqgTuZWzL0r2FKzJg7hju1SOEe4tKMxQ-xs2HyNaMM__SLsNmS3lsYZ8r2hqcjEMQQZI0T_O-3BjIpyg986P8j055E0w==",
"dp": "DujzJRw6P0L3OYQT6EBmXgSt6NTRzvZaX4SvnhU4CmOc6xynTpTamwQhwLYhjtRzb0LNyO5k-RxeLQpvlL1-A-1OWHEOeyUvim6u36a-ozm659KFLu8cIu2H2PpMuTHX4gXsIuRBmIKEk6YwpRcqbsiVpt-6BZ4yKZKY0Vou9rhSwQYTOhJLc7vYumaIVX_4szumxzdP8pcvKI_EkhRtfj3iudBnAsCIo6gqGKgkoMMD1iwkEALRW5m66w5jrywlVi6pvRiKkmOna2da1V8KvUJAYJGxT7JyP3tu64M_Wd0gFvjTg_fAT1_kJau27YlOAl2-Xso43poH_OoAzIVfxw==",
"dq": "XI6Z76z9BxB9mgcpTLc3wzw63XQNnB3bn7JRcjBwhdVD2at3uLjsL5HaAy-98kbzQfJ56kUr9sI0o_Po8yYc0ob3z80c3wpdAx2gb-dbDWVH8KJVhBOPestPzR--cEpJGlNuwkBU3mgplyKaHZamq8a46M-lB5jurEbN1mfpj3GvdSYKzdVCdSFfLqP76eCI1pblinW4b-6w-oVdn0JJ1icHPpkxVmJW-2Hok69iHcqrBtRO9AZpTsTEvKekeI4mIyhYGLi9AzzQyhV0c3GImTXFoutng5t7GyzBUoRpI0W4YeQzYa6TEzGRTylIfGPemATF_OReENp0TlLbb3gsHw==",
"qi": "m7uZk4AsOfJ1V2RY8lmEF518toCV7juKuS_b_OUx8B0dRG0_kbF1cH-Tmrgsya3bwkYx5HeZG81rX7SRjh-0nVPOMW3tGqU5U9f59DXqvOItJIJ6wvWvWXnuna2-NstYCotFQWadIKjk4wjEKj-a4NJt4D_F4csyeyqWOH2DiUFzBGGxxdEoD5t_HEeNXuWQ6-SiV0x5ZVMln3TSh7IOMl70Smm8HcQF5mOsWg3N0wIg-yffxPrs6r15TRuW1MfT-bZk2GLrtHF1TkIoT1e00jWK4eBl2oRxiJGONUBMTEHV85Fr0yztnA99AgHnrMbE_4ehvev4h5DEWvFyFuJN_g=="
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/jws-2020/v1"
],
"id": "did:key:zgghBUVkqmWS8e1ioRVp2WN9Vw6x4NvnE9PGAyQsPqM3fnfPf8EdauiRVfBTcVDyzhqM5FFC7ekAvuV1cJHawtfgB9wDcru1hPDobk3hqyedijhgWmsYfJCmodkiiFnjNWATE7PvqTyoCjcmrc8yMRXmFPnoASyT5beUd4YZxTE9VfgmavcPy3BSouNmASMQ8xUXeiRwjb7xBaVTiDRjkmyPD7NYZdXuS93gFhyDFr5b3XLg7Rfj9nHEqtHDa7NmAX7iwDAbMUFEfiDEf9hrqZmpAYJracAjTTR8Cvn6mnDXMLwayNG8dcsXFodxok2qksYF4D8ffUxMRmyyQVQhhhmdSi4YaMPqTnC1J6HTG9Yfb98yGSVaWi4TApUhLXFow2ZvB6vqckCNhjCRL2R4MDUSk71qzxWHgezKyDeyThJgdxydrn1osqH94oSeA346eipkJvKqYREXBKwgB5VL6WF4qAK6sVZxJp2dQBfCPVZ4EbsBQaJXaVK7cNcWG8tZBFWZ79gG9Cu6C4u8yjBS8Ux6dCcJPUTLtixQu4z2n5dCsVSNdnP1EEs8ZerZo5pBgc68w4Yuf9KL3xVxPnAB1nRCBfs9cMU6oL1EdyHbqrTfnjE8HpY164akBqe92LFVsk8RusaGsVPrMekT8emTq5y8v8CabuZg5rDs3f9NPEtogjyx49wiub1FecM5B7QqEcZSYiKHgF4mfkteT2",
"verificationMethod": [
{
"id": "did:key:zgghBUVkqmWS8e1ioRVp2WN9Vw6x4NvnE9PGAyQsPqM3fnfPf8EdauiRVfBTcVDyzhqM5FFC7ekAvuV1cJHawtfgB9wDcru1hPDobk3hqyedijhgWmsYfJCmodkiiFnjNWATE7PvqTyoCjcmrc8yMRXmFPnoASyT5beUd4YZxTE9VfgmavcPy3BSouNmASMQ8xUXeiRwjb7xBaVTiDRjkmyPD7NYZdXuS93gFhyDFr5b3XLg7Rfj9nHEqtHDa7NmAX7iwDAbMUFEfiDEf9hrqZmpAYJracAjTTR8Cvn6mnDXMLwayNG8dcsXFodxok2qksYF4D8ffUxMRmyyQVQhhhmdSi4YaMPqTnC1J6HTG9Yfb98yGSVaWi4TApUhLXFow2ZvB6vqckCNhjCRL2R4MDUSk71qzxWHgezKyDeyThJgdxydrn1osqH94oSeA346eipkJvKqYREXBKwgB5VL6WF4qAK6sVZxJp2dQBfCPVZ4EbsBQaJXaVK7cNcWG8tZBFWZ79gG9Cu6C4u8yjBS8Ux6dCcJPUTLtixQu4z2n5dCsVSNdnP1EEs8ZerZo5pBgc68w4Yuf9KL3xVxPnAB1nRCBfs9cMU6oL1EdyHbqrTfnjE8HpY164akBqe92LFVsk8RusaGsVPrMekT8emTq5y8v8CabuZg5rDs3f9NPEtogjyx49wiub1FecM5B7QqEcZSYiKHgF4mfkteT2#zgghBUVkqmWS8e1ioRVp2WN9Vw6x4NvnE9PGAyQsPqM3fnfPf8EdauiRVfBTcVDyzhqM5FFC7ekAvuV1cJHawtfgB9wDcru1hPDobk3hqyedijhgWmsYfJCmodkiiFnjNWATE7PvqTyoCjcmrc8yMRXmFPnoASyT5beUd4YZxTE9VfgmavcPy3BSouNmASMQ8xUXeiRwjb7xBaVTiDRjkmyPD7NYZdXuS93gFhyDFr5b3XLg7Rfj9nHEqtHDa7NmAX7iwDAbMUFEfiDEf9hrqZmpAYJracAjTTR8Cvn6mnDXMLwayNG8dcsXFodxok2qksYF4D8ffUxMRmyyQVQhhhmdSi4YaMPqTnC1J6HTG9Yfb98yGSVaWi4TApUhLXFow2ZvB6vqckCNhjCRL2R4MDUSk71qzxWHgezKyDeyThJgdxydrn1osqH94oSeA346eipkJvKqYREXBKwgB5VL6WF4qAK6sVZxJp2dQBfCPVZ4EbsBQaJXaVK7cNcWG8tZBFWZ79gG9Cu6C4u8yjBS8Ux6dCcJPUTLtixQu4z2n5dCsVSNdnP1EEs8ZerZo5pBgc68w4Yuf9KL3xVxPnAB1nRCBfs9cMU6oL1EdyHbqrTfnjE8HpY164akBqe92LFVsk8RusaGsVPrMekT8emTq5y8v8CabuZg5rDs3f9NPEtogjyx49wiub1FecM5B7QqEcZSYiKHgF4mfkteT2",
"type": "JsonWebKey2020",
"controller": "did:key:zgghBUVkqmWS8e1ioRVp2WN9Vw6x4NvnE9PGAyQsPqM3fnfPf8EdauiRVfBTcVDyzhqM5FFC7ekAvuV1cJHawtfgB9wDcru1hPDobk3hqyedijhgWmsYfJCmodkiiFnjNWATE7PvqTyoCjcmrc8yMRXmFPnoASyT5beUd4YZxTE9VfgmavcPy3BSouNmASMQ8xUXeiRwjb7xBaVTiDRjkmyPD7NYZdXuS93gFhyDFr5b3XLg7Rfj9nHEqtHDa7NmAX7iwDAbMUFEfiDEf9hrqZmpAYJracAjTTR8Cvn6mnDXMLwayNG8dcsXFodxok2qksYF4D8ffUxMRmyyQVQhhhmdSi4YaMPqTnC1J6HTG9Yfb98yGSVaWi4TApUhLXFow2ZvB6vqckCNhjCRL2R4MDUSk71qzxWHgezKyDeyThJgdxydrn1osqH94oSeA346eipkJvKqYREXBKwgB5VL6WF4qAK6sVZxJp2dQBfCPVZ4EbsBQaJXaVK7cNcWG8tZBFWZ79gG9Cu6C4u8yjBS8Ux6dCcJPUTLtixQu4z2n5dCsVSNdnP1EEs8ZerZo5pBgc68w4Yuf9KL3xVxPnAB1nRCBfs9cMU6oL1EdyHbqrTfnjE8HpY164akBqe92LFVsk8RusaGsVPrMekT8emTq5y8v8CabuZg5rDs3f9NPEtogjyx49wiub1FecM5B7QqEcZSYiKHgF4mfkteT2",
"publicKeyJwk": {
"kty": "RSA",
"n": "qMCkFFRFWtzUyZeK8mgJdyM6SEQcXC5E6JwCRVDld-jlJs8sXNOE_vliexq34wZRQ4hk53-JPFlvZ_QjRgIxdUxSMiZ3S5hlNVvvRaue6SMakA9ugQhnfXaWORro0UbPuHLms-bg5StDP8-8tIezu9c1H1FjwPcdbV6rAvKhyhnsM10qP3v2CPbdE0q3FOsihoKuTelImtO110E7N6fLn4U3EYbC4OyViqlrP1o_1M-R-tiM1cb4pD7XKJnIs6ryZdfOQSPBJwjNqSdN6Py_tdrFgPDTyacSSdpTVADOM2IMAoYbhV1N5APhnjOHBRFyKkF1HffQKpmXQLBqvUNNjuhmpVKWBtrTdcCKrglFXiw0cKGHKxIirjmiOlB_HYHg5UdosyE3_1Txct2U7-WBB6QXak1UgxCzgKYBDI8UPA0RlkUuHHP_Zg0fVXrXIInHO04MYxUeSps5qqyP6dJBu_v_BDn3zUq6LYFwJ_-xsU7zbrKYB4jaRlHPoCj_eDC-rSA2uQ4KXHBB8_aAqNFC9ukWxc26Ifz9dF968DLuL30bi-ZAa2oUh492Pw1bg89J7i4qTsOOfpQvGyDV7TGhKuUG3Hbumfr2w16S-_3EI2RIyd1nYsflE6ZmCkZQMG_lwDAFXaqfyGKEDouJuja4XH8r4fGWeGTrozIoniXT1HU",
"e": "AQAB"
}
}
],
"authentication": [
"did:key:zgghBUVkqmWS8e1ioRVp2WN9Vw6x4NvnE9PGAyQsPqM3fnfPf8EdauiRVfBTcVDyzhqM5FFC7ekAvuV1cJHawtfgB9wDcru1hPDobk3hqyedijhgWmsYfJCmodkiiFnjNWATE7PvqTyoCjcmrc8yMRXmFPnoASyT5beUd4YZxTE9VfgmavcPy3BSouNmASMQ8xUXeiRwjb7xBaVTiDRjkmyPD7NYZdXuS93gFhyDFr5b3XLg7Rfj9nHEqtHDa7NmAX7iwDAbMUFEfiDEf9hrqZmpAYJracAjTTR8Cvn6mnDXMLwayNG8dcsXFodxok2qksYF4D8ffUxMRmyyQVQhhhmdSi4YaMPqTnC1J6HTG9Yfb98yGSVaWi4TApUhLXFow2ZvB6vqckCNhjCRL2R4MDUSk71qzxWHgezKyDeyThJgdxydrn1osqH94oSeA346eipkJvKqYREXBKwgB5VL6WF4qAK6sVZxJp2dQBfCPVZ4EbsBQaJXaVK7cNcWG8tZBFWZ79gG9Cu6C4u8yjBS8Ux6dCcJPUTLtixQu4z2n5dCsVSNdnP1EEs8ZerZo5pBgc68w4Yuf9KL3xVxPnAB1nRCBfs9cMU6oL1EdyHbqrTfnjE8HpY164akBqe92LFVsk8RusaGsVPrMekT8emTq5y8v8CabuZg5rDs3f9NPEtogjyx49wiub1FecM5B7QqEcZSYiKHgF4mfkteT2#zgghBUVkqmWS8e1ioRVp2WN9Vw6x4NvnE9PGAyQsPqM3fnfPf8EdauiRVfBTcVDyzhqM5FFC7ekAvuV1cJHawtfgB9wDcru1hPDobk3hqyedijhgWmsYfJCmodkiiFnjNWATE7PvqTyoCjcmrc8yMRXmFPnoASyT5beUd4YZxTE9VfgmavcPy3BSouNmASMQ8xUXeiRwjb7xBaVTiDRjkmyPD7NYZdXuS93gFhyDFr5b3XLg7Rfj9nHEqtHDa7NmAX7iwDAbMUFEfiDEf9hrqZmpAYJracAjTTR8Cvn6mnDXMLwayNG8dcsXFodxok2qksYF4D8ffUxMRmyyQVQhhhmdSi4YaMPqTnC1J6HTG9Yfb98yGSVaWi4TApUhLXFow2ZvB6vqckCNhjCRL2R4MDUSk71qzxWHgezKyDeyThJgdxydrn1osqH94oSeA346eipkJvKqYREXBKwgB5VL6WF4qAK6sVZxJp2dQBfCPVZ4EbsBQaJXaVK7cNcWG8tZBFWZ79gG9Cu6C4u8yjBS8Ux6dCcJPUTLtixQu4z2n5dCsVSNdnP1EEs8ZerZo5pBgc68w4Yuf9KL3xVxPnAB1nRCBfs9cMU6oL1EdyHbqrTfnjE8HpY164akBqe92LFVsk8RusaGsVPrMekT8emTq5y8v8CabuZg5rDs3f9NPEtogjyx49wiub1FecM5B7QqEcZSYiKHgF4mfkteT2"
],
"assertionMethod": [
"did:key:zgghBUVkqmWS8e1ioRVp2WN9Vw6x4NvnE9PGAyQsPqM3fnfPf8EdauiRVfBTcVDyzhqM5FFC7ekAvuV1cJHawtfgB9wDcru1hPDobk3hqyedijhgWmsYfJCmodkiiFnjNWATE7PvqTyoCjcmrc8yMRXmFPnoASyT5beUd4YZxTE9VfgmavcPy3BSouNmASMQ8xUXeiRwjb7xBaVTiDRjkmyPD7NYZdXuS93gFhyDFr5b3XLg7Rfj9nHEqtHDa7NmAX7iwDAbMUFEfiDEf9hrqZmpAYJracAjTTR8Cvn6mnDXMLwayNG8dcsXFodxok2qksYF4D8ffUxMRmyyQVQhhhmdSi4YaMPqTnC1J6HTG9Yfb98yGSVaWi4TApUhLXFow2ZvB6vqckCNhjCRL2R4MDUSk71qzxWHgezKyDeyThJgdxydrn1osqH94oSeA346eipkJvKqYREXBKwgB5VL6WF4qAK6sVZxJp2dQBfCPVZ4EbsBQaJXaVK7cNcWG8tZBFWZ79gG9Cu6C4u8yjBS8Ux6dCcJPUTLtixQu4z2n5dCsVSNdnP1EEs8ZerZo5pBgc68w4Yuf9KL3xVxPnAB1nRCBfs9cMU6oL1EdyHbqrTfnjE8HpY164akBqe92LFVsk8RusaGsVPrMekT8emTq5y8v8CabuZg5rDs3f9NPEtogjyx49wiub1FecM5B7QqEcZSYiKHgF4mfkteT2#zgghBUVkqmWS8e1ioRVp2WN9Vw6x4NvnE9PGAyQsPqM3fnfPf8EdauiRVfBTcVDyzhqM5FFC7ekAvuV1cJHawtfgB9wDcru1hPDobk3hqyedijhgWmsYfJCmodkiiFnjNWATE7PvqTyoCjcmrc8yMRXmFPnoASyT5beUd4YZxTE9VfgmavcPy3BSouNmASMQ8xUXeiRwjb7xBaVTiDRjkmyPD7NYZdXuS93gFhyDFr5b3XLg7Rfj9nHEqtHDa7NmAX7iwDAbMUFEfiDEf9hrqZmpAYJracAjTTR8Cvn6mnDXMLwayNG8dcsXFodxok2qksYF4D8ffUxMRmyyQVQhhhmdSi4YaMPqTnC1J6HTG9Yfb98yGSVaWi4TApUhLXFow2ZvB6vqckCNhjCRL2R4MDUSk71qzxWHgezKyDeyThJgdxydrn1osqH94oSeA346eipkJvKqYREXBKwgB5VL6WF4qAK6sVZxJp2dQBfCPVZ4EbsBQaJXaVK7cNcWG8tZBFWZ79gG9Cu6C4u8yjBS8Ux6dCcJPUTLtixQu4z2n5dCsVSNdnP1EEs8ZerZo5pBgc68w4Yuf9KL3xVxPnAB1nRCBfs9cMU6oL1EdyHbqrTfnjE8HpY164akBqe92LFVsk8RusaGsVPrMekT8emTq5y8v8CabuZg5rDs3f9NPEtogjyx49wiub1FecM5B7QqEcZSYiKHgF4mfkteT2"
],
"capabilityDelegation": [
"did:key:zgghBUVkqmWS8e1ioRVp2WN9Vw6x4NvnE9PGAyQsPqM3fnfPf8EdauiRVfBTcVDyzhqM5FFC7ekAvuV1cJHawtfgB9wDcru1hPDobk3hqyedijhgWmsYfJCmodkiiFnjNWATE7PvqTyoCjcmrc8yMRXmFPnoASyT5beUd4YZxTE9VfgmavcPy3BSouNmASMQ8xUXeiRwjb7xBaVTiDRjkmyPD7NYZdXuS93gFhyDFr5b3XLg7Rfj9nHEqtHDa7NmAX7iwDAbMUFEfiDEf9hrqZmpAYJracAjTTR8Cvn6mnDXMLwayNG8dcsXFodxok2qksYF4D8ffUxMRmyyQVQhhhmdSi4YaMPqTnC1J6HTG9Yfb98yGSVaWi4TApUhLXFow2ZvB6vqckCNhjCRL2R4MDUSk71qzxWHgezKyDeyThJgdxydrn1osqH94oSeA346eipkJvKqYREXBKwgB5VL6WF4qAK6sVZxJp2dQBfCPVZ4EbsBQaJXaVK7cNcWG8tZBFWZ79gG9Cu6C4u8yjBS8Ux6dCcJPUTLtixQu4z2n5dCsVSNdnP1EEs8ZerZo5pBgc68w4Yuf9KL3xVxPnAB1nRCBfs9cMU6oL1EdyHbqrTfnjE8HpY164akBqe92LFVsk8RusaGsVPrMekT8emTq5y8v8CabuZg5rDs3f9NPEtogjyx49wiub1FecM5B7QqEcZSYiKHgF4mfkteT2#zgghBUVkqmWS8e1ioRVp2WN9Vw6x4NvnE9PGAyQsPqM3fnfPf8EdauiRVfBTcVDyzhqM5FFC7ekAvuV1cJHawtfgB9wDcru1hPDobk3hqyedijhgWmsYfJCmodkiiFnjNWATE7PvqTyoCjcmrc8yMRXmFPnoASyT5beUd4YZxTE9VfgmavcPy3BSouNmASMQ8xUXeiRwjb7xBaVTiDRjkmyPD7NYZdXuS93gFhyDFr5b3XLg7Rfj9nHEqtHDa7NmAX7iwDAbMUFEfiDEf9hrqZmpAYJracAjTTR8Cvn6mnDXMLwayNG8dcsXFodxok2qksYF4D8ffUxMRmyyQVQhhhmdSi4YaMPqTnC1J6HTG9Yfb98yGSVaWi4TApUhLXFow2ZvB6vqckCNhjCRL2R4MDUSk71qzxWHgezKyDeyThJgdxydrn1osqH94oSeA346eipkJvKqYREXBKwgB5VL6WF4qAK6sVZxJp2dQBfCPVZ4EbsBQaJXaVK7cNcWG8tZBFWZ79gG9Cu6C4u8yjBS8Ux6dCcJPUTLtixQu4z2n5dCsVSNdnP1EEs8ZerZo5pBgc68w4Yuf9KL3xVxPnAB1nRCBfs9cMU6oL1EdyHbqrTfnjE8HpY164akBqe92LFVsk8RusaGsVPrMekT8emTq5y8v8CabuZg5rDs3f9NPEtogjyx49wiub1FecM5B7QqEcZSYiKHgF4mfkteT2"
],
"capabilityInvocation": [
"did:key:zgghBUVkqmWS8e1ioRVp2WN9Vw6x4NvnE9PGAyQsPqM3fnfPf8EdauiRVfBTcVDyzhqM5FFC7ekAvuV1cJHawtfgB9wDcru1hPDobk3hqyedijhgWmsYfJCmodkiiFnjNWATE7PvqTyoCjcmrc8yMRXmFPnoASyT5beUd4YZxTE9VfgmavcPy3BSouNmASMQ8xUXeiRwjb7xBaVTiDRjkmyPD7NYZdXuS93gFhyDFr5b3XLg7Rfj9nHEqtHDa7NmAX7iwDAbMUFEfiDEf9hrqZmpAYJracAjTTR8Cvn6mnDXMLwayNG8dcsXFodxok2qksYF4D8ffUxMRmyyQVQhhhmdSi4YaMPqTnC1J6HTG9Yfb98yGSVaWi4TApUhLXFow2ZvB6vqckCNhjCRL2R4MDUSk71qzxWHgezKyDeyThJgdxydrn1osqH94oSeA346eipkJvKqYREXBKwgB5VL6WF4qAK6sVZxJp2dQBfCPVZ4EbsBQaJXaVK7cNcWG8tZBFWZ79gG9Cu6C4u8yjBS8Ux6dCcJPUTLtixQu4z2n5dCsVSNdnP1EEs8ZerZo5pBgc68w4Yuf9KL3xVxPnAB1nRCBfs9cMU6oL1EdyHbqrTfnjE8HpY164akBqe92LFVsk8RusaGsVPrMekT8emTq5y8v8CabuZg5rDs3f9NPEtogjyx49wiub1FecM5B7QqEcZSYiKHgF4mfkteT2#zgghBUVkqmWS8e1ioRVp2WN9Vw6x4NvnE9PGAyQsPqM3fnfPf8EdauiRVfBTcVDyzhqM5FFC7ekAvuV1cJHawtfgB9wDcru1hPDobk3hqyedijhgWmsYfJCmodkiiFnjNWATE7PvqTyoCjcmrc8yMRXmFPnoASyT5beUd4YZxTE9VfgmavcPy3BSouNmASMQ8xUXeiRwjb7xBaVTiDRjkmyPD7NYZdXuS93gFhyDFr5b3XLg7Rfj9nHEqtHDa7NmAX7iwDAbMUFEfiDEf9hrqZmpAYJracAjTTR8Cvn6mnDXMLwayNG8dcsXFodxok2qksYF4D8ffUxMRmyyQVQhhhmdSi4YaMPqTnC1J6HTG9Yfb98yGSVaWi4TApUhLXFow2ZvB6vqckCNhjCRL2R4MDUSk71qzxWHgezKyDeyThJgdxydrn1osqH94oSeA346eipkJvKqYREXBKwgB5VL6WF4qAK6sVZxJp2dQBfCPVZ4EbsBQaJXaVK7cNcWG8tZBFWZ79gG9Cu6C4u8yjBS8Ux6dCcJPUTLtixQu4z2n5dCsVSNdnP1EEs8ZerZo5pBgc68w4Yuf9KL3xVxPnAB1nRCBfs9cMU6oL1EdyHbqrTfnjE8HpY164akBqe92LFVsk8RusaGsVPrMekT8emTq5y8v8CabuZg5rDs3f9NPEtogjyx49wiub1FecM5B7QqEcZSYiKHgF4mfkteT2"
],
"keyAgreement": [
"did:key:zgghBUVkqmWS8e1ioRVp2WN9Vw6x4NvnE9PGAyQsPqM3fnfPf8EdauiRVfBTcVDyzhqM5FFC7ekAvuV1cJHawtfgB9wDcru1hPDobk3hqyedijhgWmsYfJCmodkiiFnjNWATE7PvqTyoCjcmrc8yMRXmFPnoASyT5beUd4YZxTE9VfgmavcPy3BSouNmASMQ8xUXeiRwjb7xBaVTiDRjkmyPD7NYZdXuS93gFhyDFr5b3XLg7Rfj9nHEqtHDa7NmAX7iwDAbMUFEfiDEf9hrqZmpAYJracAjTTR8Cvn6mnDXMLwayNG8dcsXFodxok2qksYF4D8ffUxMRmyyQVQhhhmdSi4YaMPqTnC1J6HTG9Yfb98yGSVaWi4TApUhLXFow2ZvB6vqckCNhjCRL2R4MDUSk71qzxWHgezKyDeyThJgdxydrn1osqH94oSeA346eipkJvKqYREXBKwgB5VL6WF4qAK6sVZxJp2dQBfCPVZ4EbsBQaJXaVK7cNcWG8tZBFWZ79gG9Cu6C4u8yjBS8Ux6dCcJPUTLtixQu4z2n5dCsVSNdnP1EEs8ZerZo5pBgc68w4Yuf9KL3xVxPnAB1nRCBfs9cMU6oL1EdyHbqrTfnjE8HpY164akBqe92LFVsk8RusaGsVPrMekT8emTq5y8v8CabuZg5rDs3f9NPEtogjyx49wiub1FecM5B7QqEcZSYiKHgF4mfkteT2#zgghBUVkqmWS8e1ioRVp2WN9Vw6x4NvnE9PGAyQsPqM3fnfPf8EdauiRVfBTcVDyzhqM5FFC7ekAvuV1cJHawtfgB9wDcru1hPDobk3hqyedijhgWmsYfJCmodkiiFnjNWATE7PvqTyoCjcmrc8yMRXmFPnoASyT5beUd4YZxTE9VfgmavcPy3BSouNmASMQ8xUXeiRwjb7xBaVTiDRjkmyPD7NYZdXuS93gFhyDFr5b3XLg7Rfj9nHEqtHDa7NmAX7iwDAbMUFEfiDEf9hrqZmpAYJracAjTTR8Cvn6mnDXMLwayNG8dcsXFodxok2qksYF4D8ffUxMRmyyQVQhhhmdSi4YaMPqTnC1J6HTG9Yfb98yGSVaWi4TApUhLXFow2ZvB6vqckCNhjCRL2R4MDUSk71qzxWHgezKyDeyThJgdxydrn1osqH94oSeA346eipkJvKqYREXBKwgB5VL6WF4qAK6sVZxJp2dQBfCPVZ4EbsBQaJXaVK7cNcWG8tZBFWZ79gG9Cu6C4u8yjBS8Ux6dCcJPUTLtixQu4z2n5dCsVSNdnP1EEs8ZerZo5pBgc68w4Yuf9KL3xVxPnAB1nRCBfs9cMU6oL1EdyHbqrTfnjE8HpY164akBqe92LFVsk8RusaGsVPrMekT8emTq5y8v8CabuZg5rDs3f9NPEtogjyx49wiub1FecM5B7QqEcZSYiKHgF4mfkteT2"
]
}
}
}

View File

@@ -1,257 +0,0 @@
{
"did:key:zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme": {
"seed": "9085d2bef69286a6cbb51623c8fa258629945cd55ca705cc4e66700396894e0c",
"verificationKeyPair": {
"id": "#zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme",
"type": "EcdsaSecp256k1VerificationKey2019",
"controller": "did:key:zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme",
"publicKeyBase58": "23o6Sau8NxxzXcgSc3PLcNxrzrZpbLeBn1izfv3jbKhuv",
"privateKeyBase58": "AjA4cyPUbbfW5wr6iZeRbJLhgH3qDt6q6LMkRw36KpxT"
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/secp256k1-2019/v1"
],
"id": "did:key:zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme",
"verificationMethod": [
{
"id": "did:key:zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme#zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme",
"type": "EcdsaSecp256k1VerificationKey2019",
"controller": "did:key:zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme",
"publicKeyBase58": "23o6Sau8NxxzXcgSc3PLcNxrzrZpbLeBn1izfv3jbKhuv"
}
],
"assertionMethod": [
"did:key:zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme#zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme"
],
"authentication": [
"did:key:zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme#zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme"
],
"capabilityInvocation": [
"did:key:zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme#zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme"
],
"capabilityDelegation": [
"did:key:zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme#zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme"
],
"keyAgreement": [
"did:key:zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme#zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme"
]
}
},
"did:key:zQ3shtxV1FrJfhqE1dvxYRcCknWNjHc3c5X1y3ZSoPDi2aur2": {
"seed": "f0f4df55a2b3ff13051ea814a8f24ad00f2e469af73c363ac7e9fb999a9072ed",
"verificationKeyPair": {
"id": "#zQ3shtxV1FrJfhqE1dvxYRcCknWNjHc3c5X1y3ZSoPDi2aur2",
"type": "EcdsaSecp256k1VerificationKey2019",
"controller": "did:key:zQ3shtxV1FrJfhqE1dvxYRcCknWNjHc3c5X1y3ZSoPDi2aur2",
"publicKeyBase58": "291KzQhqCPC18PqH83XKhxv1HdqrdnxyS7dh15t2uNRzJ",
"privateKeyBase58": "HDbR1D5W3CoNbUKYzUbHH2PRF1atshtVupXgXTQhNB9E"
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/secp256k1-2019/v1"
],
"id": "did:key:zQ3shtxV1FrJfhqE1dvxYRcCknWNjHc3c5X1y3ZSoPDi2aur2",
"verificationMethod": [
{
"id": "did:key:zQ3shtxV1FrJfhqE1dvxYRcCknWNjHc3c5X1y3ZSoPDi2aur2#zQ3shtxV1FrJfhqE1dvxYRcCknWNjHc3c5X1y3ZSoPDi2aur2",
"type": "EcdsaSecp256k1VerificationKey2019",
"controller": "did:key:zQ3shtxV1FrJfhqE1dvxYRcCknWNjHc3c5X1y3ZSoPDi2aur2",
"publicKeyBase58": "291KzQhqCPC18PqH83XKhxv1HdqrdnxyS7dh15t2uNRzJ"
}
],
"assertionMethod": [
"did:key:zQ3shtxV1FrJfhqE1dvxYRcCknWNjHc3c5X1y3ZSoPDi2aur2#zQ3shtxV1FrJfhqE1dvxYRcCknWNjHc3c5X1y3ZSoPDi2aur2"
],
"authentication": [
"did:key:zQ3shtxV1FrJfhqE1dvxYRcCknWNjHc3c5X1y3ZSoPDi2aur2#zQ3shtxV1FrJfhqE1dvxYRcCknWNjHc3c5X1y3ZSoPDi2aur2"
],
"capabilityInvocation": [
"did:key:zQ3shtxV1FrJfhqE1dvxYRcCknWNjHc3c5X1y3ZSoPDi2aur2#zQ3shtxV1FrJfhqE1dvxYRcCknWNjHc3c5X1y3ZSoPDi2aur2"
],
"capabilityDelegation": [
"did:key:zQ3shtxV1FrJfhqE1dvxYRcCknWNjHc3c5X1y3ZSoPDi2aur2#zQ3shtxV1FrJfhqE1dvxYRcCknWNjHc3c5X1y3ZSoPDi2aur2"
],
"keyAgreement": [
"did:key:zQ3shtxV1FrJfhqE1dvxYRcCknWNjHc3c5X1y3ZSoPDi2aur2#zQ3shtxV1FrJfhqE1dvxYRcCknWNjHc3c5X1y3ZSoPDi2aur2"
]
}
},
"did:key:zQ3shZc2QzApp2oymGvQbzP8eKheVshBHbU4ZYjeXqwSKEn6N": {
"seed": "6b0b91287ae3348f8c2f2552d766f30e3604867e34adc37ccbb74a8e6b893e02",
"verificationKeyPair": {
"id": "#zQ3shZc2QzApp2oymGvQbzP8eKheVshBHbU4ZYjeXqwSKEn6N",
"type": "EcdsaSecp256k1VerificationKey2019",
"controller": "did:key:zQ3shZc2QzApp2oymGvQbzP8eKheVshBHbU4ZYjeXqwSKEn6N",
"publicKeyBase58": "oesQ92MLiAkt2pjBcJFbW7H4DvzKJv22cotjYbmC2JEe",
"privateKeyBase58": "8CrrWVdzDnvaS7vS5dd2HetFSebwEN46XEFrNDdtWZSZ"
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/secp256k1-2019/v1"
],
"id": "did:key:zQ3shZc2QzApp2oymGvQbzP8eKheVshBHbU4ZYjeXqwSKEn6N",
"verificationMethod": [
{
"id": "did:key:zQ3shZc2QzApp2oymGvQbzP8eKheVshBHbU4ZYjeXqwSKEn6N#zQ3shZc2QzApp2oymGvQbzP8eKheVshBHbU4ZYjeXqwSKEn6N",
"type": "EcdsaSecp256k1VerificationKey2019",
"controller": "did:key:zQ3shZc2QzApp2oymGvQbzP8eKheVshBHbU4ZYjeXqwSKEn6N",
"publicKeyBase58": "oesQ92MLiAkt2pjBcJFbW7H4DvzKJv22cotjYbmC2JEe"
}
],
"assertionMethod": [
"did:key:zQ3shZc2QzApp2oymGvQbzP8eKheVshBHbU4ZYjeXqwSKEn6N#zQ3shZc2QzApp2oymGvQbzP8eKheVshBHbU4ZYjeXqwSKEn6N"
],
"authentication": [
"did:key:zQ3shZc2QzApp2oymGvQbzP8eKheVshBHbU4ZYjeXqwSKEn6N#zQ3shZc2QzApp2oymGvQbzP8eKheVshBHbU4ZYjeXqwSKEn6N"
],
"capabilityInvocation": [
"did:key:zQ3shZc2QzApp2oymGvQbzP8eKheVshBHbU4ZYjeXqwSKEn6N#zQ3shZc2QzApp2oymGvQbzP8eKheVshBHbU4ZYjeXqwSKEn6N"
],
"capabilityDelegation": [
"did:key:zQ3shZc2QzApp2oymGvQbzP8eKheVshBHbU4ZYjeXqwSKEn6N#zQ3shZc2QzApp2oymGvQbzP8eKheVshBHbU4ZYjeXqwSKEn6N"
],
"keyAgreement": [
"did:key:zQ3shZc2QzApp2oymGvQbzP8eKheVshBHbU4ZYjeXqwSKEn6N#zQ3shZc2QzApp2oymGvQbzP8eKheVshBHbU4ZYjeXqwSKEn6N"
]
}
},
"did:key:zQ3shadCps5JLAHcZiuX5YUtWHHL8ysBJqFLWvjZDKAWUBGzy": {
"seed": "c0a6a7c560d37d7ba81ecee9543721ff48fea3e0fb827d42c1868226540fac15",
"verificationKeyPair": {
"id": "#zQ3shadCps5JLAHcZiuX5YUtWHHL8ysBJqFLWvjZDKAWUBGzy",
"type": "EcdsaSecp256k1VerificationKey2019",
"controller": "did:key:zQ3shadCps5JLAHcZiuX5YUtWHHL8ysBJqFLWvjZDKAWUBGzy",
"publicKeyBase58": "pg3p1vprqePgUoqfAQ1TTgxhL6zLYhHyzooR1pqLxo9F",
"privateKeyBase58": "Dy2fnt8ba4NmbRBXas9bo1BtYgpYFr6ThpFhJbuA3PRn"
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/secp256k1-2019/v1"
],
"id": "did:key:zQ3shadCps5JLAHcZiuX5YUtWHHL8ysBJqFLWvjZDKAWUBGzy",
"verificationMethod": [
{
"id": "did:key:zQ3shadCps5JLAHcZiuX5YUtWHHL8ysBJqFLWvjZDKAWUBGzy#zQ3shadCps5JLAHcZiuX5YUtWHHL8ysBJqFLWvjZDKAWUBGzy",
"type": "EcdsaSecp256k1VerificationKey2019",
"controller": "did:key:zQ3shadCps5JLAHcZiuX5YUtWHHL8ysBJqFLWvjZDKAWUBGzy",
"publicKeyBase58": "pg3p1vprqePgUoqfAQ1TTgxhL6zLYhHyzooR1pqLxo9F"
}
],
"assertionMethod": [
"did:key:zQ3shadCps5JLAHcZiuX5YUtWHHL8ysBJqFLWvjZDKAWUBGzy#zQ3shadCps5JLAHcZiuX5YUtWHHL8ysBJqFLWvjZDKAWUBGzy"
],
"authentication": [
"did:key:zQ3shadCps5JLAHcZiuX5YUtWHHL8ysBJqFLWvjZDKAWUBGzy#zQ3shadCps5JLAHcZiuX5YUtWHHL8ysBJqFLWvjZDKAWUBGzy"
],
"capabilityInvocation": [
"did:key:zQ3shadCps5JLAHcZiuX5YUtWHHL8ysBJqFLWvjZDKAWUBGzy#zQ3shadCps5JLAHcZiuX5YUtWHHL8ysBJqFLWvjZDKAWUBGzy"
],
"capabilityDelegation": [
"did:key:zQ3shadCps5JLAHcZiuX5YUtWHHL8ysBJqFLWvjZDKAWUBGzy#zQ3shadCps5JLAHcZiuX5YUtWHHL8ysBJqFLWvjZDKAWUBGzy"
],
"keyAgreement": [
"did:key:zQ3shadCps5JLAHcZiuX5YUtWHHL8ysBJqFLWvjZDKAWUBGzy#zQ3shadCps5JLAHcZiuX5YUtWHHL8ysBJqFLWvjZDKAWUBGzy"
]
}
},
"did:key:zQ3shptjE6JwdkeKN4fcpnYQY3m9Cet3NiHdAfpvSUZBFoKBj": {
"seed": "175a232d440be1e0788f25488a73d9416c04b6f924bea6354bf05dd2f1a75133",
"verificationKeyPair": {
"id": "#zQ3shptjE6JwdkeKN4fcpnYQY3m9Cet3NiHdAfpvSUZBFoKBj",
"type": "EcdsaSecp256k1VerificationKey2019",
"controller": "did:key:zQ3shptjE6JwdkeKN4fcpnYQY3m9Cet3NiHdAfpvSUZBFoKBj",
"publicKeyBase58": "24waDFAUAS16UpZwQQTXVEAmm17rQRjadjuAeBDW8aqL1",
"privateKeyBase58": "2aA6WgZnPiVMBX3LvKSTg3KaFKyzfKpvEacixB3yyTgv"
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/secp256k1-2019/v1"
],
"id": "did:key:zQ3shptjE6JwdkeKN4fcpnYQY3m9Cet3NiHdAfpvSUZBFoKBj",
"verificationMethod": [
{
"id": "did:key:zQ3shptjE6JwdkeKN4fcpnYQY3m9Cet3NiHdAfpvSUZBFoKBj#zQ3shptjE6JwdkeKN4fcpnYQY3m9Cet3NiHdAfpvSUZBFoKBj",
"type": "EcdsaSecp256k1VerificationKey2019",
"controller": "did:key:zQ3shptjE6JwdkeKN4fcpnYQY3m9Cet3NiHdAfpvSUZBFoKBj",
"publicKeyBase58": "24waDFAUAS16UpZwQQTXVEAmm17rQRjadjuAeBDW8aqL1"
}
],
"assertionMethod": [
"did:key:zQ3shptjE6JwdkeKN4fcpnYQY3m9Cet3NiHdAfpvSUZBFoKBj#zQ3shptjE6JwdkeKN4fcpnYQY3m9Cet3NiHdAfpvSUZBFoKBj"
],
"authentication": [
"did:key:zQ3shptjE6JwdkeKN4fcpnYQY3m9Cet3NiHdAfpvSUZBFoKBj#zQ3shptjE6JwdkeKN4fcpnYQY3m9Cet3NiHdAfpvSUZBFoKBj"
],
"capabilityInvocation": [
"did:key:zQ3shptjE6JwdkeKN4fcpnYQY3m9Cet3NiHdAfpvSUZBFoKBj#zQ3shptjE6JwdkeKN4fcpnYQY3m9Cet3NiHdAfpvSUZBFoKBj"
],
"capabilityDelegation": [
"did:key:zQ3shptjE6JwdkeKN4fcpnYQY3m9Cet3NiHdAfpvSUZBFoKBj#zQ3shptjE6JwdkeKN4fcpnYQY3m9Cet3NiHdAfpvSUZBFoKBj"
],
"keyAgreement": [
"did:key:zQ3shptjE6JwdkeKN4fcpnYQY3m9Cet3NiHdAfpvSUZBFoKBj#zQ3shptjE6JwdkeKN4fcpnYQY3m9Cet3NiHdAfpvSUZBFoKBj"
]
}
},
"did:key:zQ3shjmnWpSDEbYKpaFm4kTs9kXyqG6N2QwCYHNPP4yubqgJS": {
"verificationKeyPair": {
"id": "did:key:zQ3shjmnWpSDEbYKpaFm4kTs9kXyqG6N2QwCYHNPP4yubqgJS#zQ3shjmnWpSDEbYKpaFm4kTs9kXyqG6N2QwCYHNPP4yubqgJS",
"type": "JsonWebKey2020",
"controller": "did:key:zQ3shjmnWpSDEbYKpaFm4kTs9kXyqG6N2QwCYHNPP4yubqgJS",
"publicKeyJwk": {
"kty": "EC",
"crv": "secp256k1",
"x": "TEIJN9vnTq1EXMkqzo7yN_867-foKc2pREv45Fw_QA8",
"y": "9yiymlzdxKCiRbYq7p-ArRB-C1ytjHE-eb7RDTi6rVc"
},
"privateKeyJwk": {
"kty": "EC",
"crv": "secp256k1",
"x": "TEIJN9vnTq1EXMkqzo7yN_867-foKc2pREv45Fw_QA8",
"y": "9yiymlzdxKCiRbYq7p-ArRB-C1ytjHE-eb7RDTi6rVc",
"d": "J5yKm7OXFsXDEutteGYeT0CAfQJwIlHLSYkQxKtgiyo"
}
},
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/jws-2020/v1"
],
"id": "did:key:zQ3shjmnWpSDEbYKpaFm4kTs9kXyqG6N2QwCYHNPP4yubqgJS",
"verificationMethod": [
{
"id": "did:key:zQ3shjmnWpSDEbYKpaFm4kTs9kXyqG6N2QwCYHNPP4yubqgJS#zQ3shjmnWpSDEbYKpaFm4kTs9kXyqG6N2QwCYHNPP4yubqgJS",
"type": "JsonWebKey2020",
"controller": "did:key:zQ3shjmnWpSDEbYKpaFm4kTs9kXyqG6N2QwCYHNPP4yubqgJS",
"publicKeyJwk": {
"kty": "EC",
"crv": "secp256k1",
"x": "TEIJN9vnTq1EXMkqzo7yN_867-foKc2pREv45Fw_QA8",
"y": "9yiymlzdxKCiRbYq7p-ArRB-C1ytjHE-eb7RDTi6rVc"
}
}
],
"assertionMethod": [
"did:key:zQ3shjmnWpSDEbYKpaFm4kTs9kXyqG6N2QwCYHNPP4yubqgJS#zQ3shjmnWpSDEbYKpaFm4kTs9kXyqG6N2QwCYHNPP4yubqgJS"
],
"authentication": [
"did:key:zQ3shjmnWpSDEbYKpaFm4kTs9kXyqG6N2QwCYHNPP4yubqgJS#zQ3shjmnWpSDEbYKpaFm4kTs9kXyqG6N2QwCYHNPP4yubqgJS"
],
"capabilityInvocation": [
"did:key:zQ3shjmnWpSDEbYKpaFm4kTs9kXyqG6N2QwCYHNPP4yubqgJS#zQ3shjmnWpSDEbYKpaFm4kTs9kXyqG6N2QwCYHNPP4yubqgJS"
],
"capabilityDelegation": [
"did:key:zQ3shjmnWpSDEbYKpaFm4kTs9kXyqG6N2QwCYHNPP4yubqgJS#zQ3shjmnWpSDEbYKpaFm4kTs9kXyqG6N2QwCYHNPP4yubqgJS"
],
"keyAgreement": [
"did:key:zQ3shjmnWpSDEbYKpaFm4kTs9kXyqG6N2QwCYHNPP4yubqgJS#zQ3shjmnWpSDEbYKpaFm4kTs9kXyqG6N2QwCYHNPP4yubqgJS"
]
}
}
}

View File

@@ -1,163 +0,0 @@
//go:build jwx_es256k
package testvectors
import (
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rsa"
"crypto/x509"
"encoding/json"
"errors"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/lestrrat-go/jwx/v2/jwk"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/mr-tron/base58"
)
type Vectors map[string]Vector
// This is pretty gross but the structure allows the repeated Verifier,
// PublicKeyJwk and PublicKeyBase58 account for the fact that the test
// files are very inconsistent.
type Vector struct {
VerificationKeyPair Verifier
VerificationMethod Verifier
PublicKeyJwk json.RawMessage
DidDocument json.RawMessage // TODO: if we start producing DID documents, we should test this too
}
type Verifier struct {
ID string
Type string
PublicKeyBase58 string
PublicKeyJwk json.RawMessage
}
func (v Vector) PubKey() (crypto.PubKey, error) {
// If the public key is in base58
if pubB58 := v.PubKeyBase58(); len(pubB58) > 0 {
pubBytes, err := base58.Decode(pubB58)
if err != nil {
return nil, err
}
t, err := v.PubKeyType()
if err != nil {
return nil, err
}
var unmarshaler crypto.PubKeyUnmarshaller
switch t {
case "Ed25519VerificationKey2018":
unmarshaler = crypto.UnmarshalEd25519PublicKey
case "EcdsaSecp256k1VerificationKey2019":
unmarshaler = crypto.UnmarshalSecp256k1PublicKey
// This is weak as it assumes the P256 curve - that's all the vectors contain (for now)
case "P256Key2021":
unmarshaler = compressedEcdsaPublicKeyUnmarshaler
default:
return nil, errors.New("failed to resolve unmarshaler")
}
return unmarshaler(pubBytes)
}
// If the public key is in a JWK
if pubJwk := v.PubKeyJwk(); len(pubJwk) > 0 {
key, err := jwk.ParseKey(pubJwk)
if err != nil {
return nil, err
}
var a any
if err := key.Raw(&a); err != nil {
return nil, err
}
switch a.(type) {
case *ecdsa.PublicKey:
epub := a.(*ecdsa.PublicKey)
if epub.Curve == secp256k1.S256() {
bytes := append([]byte{0x04}, append(epub.X.Bytes(), epub.Y.Bytes()...)...)
return crypto.UnmarshalSecp256k1PublicKey(bytes)
}
asn1, err := x509.MarshalPKIXPublicKey(epub)
if err != nil {
return nil, err
}
return crypto.UnmarshalECDSAPublicKey(asn1)
case ed25519.PublicKey:
return crypto.UnmarshalEd25519PublicKey(a.(ed25519.PublicKey))
case *rsa.PublicKey:
asn1, err := x509.MarshalPKIXPublicKey(a.(*rsa.PublicKey))
if err != nil {
return nil, err
}
return crypto.UnmarshalRsaPublicKey(asn1)
default:
return nil, errors.New("unsupported key type")
}
}
// If we don't find a public key at all
return nil, errors.New("vector's public key not found")
}
func (v Vector) PubKeyBase58() string {
if len(v.VerificationKeyPair.PublicKeyBase58) > 0 {
return v.VerificationKeyPair.PublicKeyBase58
}
return v.VerificationMethod.PublicKeyBase58
}
func (v Vector) PubKeyJwk() json.RawMessage {
if len(v.VerificationKeyPair.PublicKeyJwk) > 0 {
return v.VerificationKeyPair.PublicKeyJwk
}
if len(v.VerificationMethod.PublicKeyJwk) > 0 {
return v.VerificationMethod.PublicKeyJwk
}
return v.PublicKeyJwk
}
func (v Vector) PubKeyType() (string, error) {
if len(v.VerificationKeyPair.Type) > 0 {
return v.VerificationKeyPair.Type, nil
}
if len(v.VerificationMethod.Type) > 0 {
return v.VerificationMethod.Type, nil
}
return "", errors.New("vector's type not found")
}
func compressedEcdsaPublicKeyUnmarshaler(data []byte) (crypto.PubKey, error) {
x, y := elliptic.UnmarshalCompressed(elliptic.P256(), data)
ecdsaPublicKey := ecdsa.PublicKey{
Curve: elliptic.P256(),
X: x,
Y: y,
}
asn1, err := x509.MarshalPKIXPublicKey(&ecdsaPublicKey)
if err != nil {
return nil, err
}
return crypto.UnmarshalECDSAPublicKey(asn1)
}

View File

@@ -1,80 +0,0 @@
{
"didDocument": {
"did:key:z6LSeu9HkTHSfLLeUs2nnzUSNedgDUevfNQgQjQC23ZCit6F": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/x25519-2019/v1"
],
"id": "did:key:z6LSeu9HkTHSfLLeUs2nnzUSNedgDUevfNQgQjQC23ZCit6F",
"verificationMethod": [
{
"id": "did:key:z6LSeu9HkTHSfLLeUs2nnzUSNedgDUevfNQgQjQC23ZCit6F#z6LSeu9HkTHSfLLeUs2nnzUSNedgDUevfNQgQjQC23ZCit6F",
"type": "X25519KeyAgreementKey2019",
"controller": "did:key:z6LSeu9HkTHSfLLeUs2nnzUSNedgDUevfNQgQjQC23ZCit6F",
"publicKeyBase58": "4Dy8E9UaZscuPUf2GLxV44RCNL7oxmEXXkgWXaug1WKV"
}
],
"keyAgreement": [
"did:key:z6LSeu9HkTHSfLLeUs2nnzUSNedgDUevfNQgQjQC23ZCit6F#z6LSeu9HkTHSfLLeUs2nnzUSNedgDUevfNQgQjQC23ZCit6F"
]
},
"did:key:z6LStiZsmxiK4odS4Sb6JmdRFuJ6e1SYP157gtiCyJKfrYha": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/x25519-2019/v1"
],
"id": "did:key:z6LStiZsmxiK4odS4Sb6JmdRFuJ6e1SYP157gtiCyJKfrYha",
"verificationMethod": [
{
"id": "did:key:z6LStiZsmxiK4odS4Sb6JmdRFuJ6e1SYP157gtiCyJKfrYha#z6LStiZsmxiK4odS4Sb6JmdRFuJ6e1SYP157gtiCyJKfrYha",
"type": "X25519KeyAgreementKey2019",
"controller": "did:key:z6LStiZsmxiK4odS4Sb6JmdRFuJ6e1SYP157gtiCyJKfrYha",
"publicKeyBase58": "J3PiFeuSyLugy4DKn87TwK5cnruRgPtxouzXUqg99Avp"
}
],
"keyAgreement": [
"did:key:z6LStiZsmxiK4odS4Sb6JmdRFuJ6e1SYP157gtiCyJKfrYha#z6LStiZsmxiK4odS4Sb6JmdRFuJ6e1SYP157gtiCyJKfrYha"
]
},
"did:key:z6LSoMdmJz2Djah2P4L9taDmtqeJ6wwd2HhKZvNToBmvaczQ": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/x25519-2019/v1"
],
"id": "did:key:z6LSoMdmJz2Djah2P4L9taDmtqeJ6wwd2HhKZvNToBmvaczQ",
"verificationMethod": [
{
"id": "did:key:z6LSoMdmJz2Djah2P4L9taDmtqeJ6wwd2HhKZvNToBmvaczQ#z6LSoMdmJz2Djah2P4L9taDmtqeJ6wwd2HhKZvNToBmvaczQ",
"type": "X25519KeyAgreementKey2019",
"controller": "did:key:z6LSoMdmJz2Djah2P4L9taDmtqeJ6wwd2HhKZvNToBmvaczQ",
"publicKeyBase58": "CgTbngDMe7yHHfxPMvhpaFRpFoQWKgXAgwenJj8PsFDe"
}
],
"keyAgreement": [
"did:key:z6LSoMdmJz2Djah2P4L9taDmtqeJ6wwd2HhKZvNToBmvaczQ#z6LSoMdmJz2Djah2P4L9taDmtqeJ6wwd2HhKZvNToBmvaczQ"
]
},
"did:key:z6LSrzxMVydCourtpA6JLEYupT7ZUQ34hLfQZfRN5H47zLdz": {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/jws-2020/v1"
],
"id": "did:key:z6LSrzxMVydCourtpA6JLEYupT7ZUQ34hLfQZfRN5H47zLdz",
"verificationMethod": [
{
"id": "did:key:z6LSrzxMVydCourtpA6JLEYupT7ZUQ34hLfQZfRN5H47zLdz#z6LSrzxMVydCourtpA6JLEYupT7ZUQ34hLfQZfRN5H47zLdz",
"type": "JsonWebKey2020",
"controller": "did:key:z6LSrzxMVydCourtpA6JLEYupT7ZUQ34hLfQZfRN5H47zLdz",
"publicKeyJwk": {
"kty": "OKP",
"crv": "X25519",
"x": "467ap28wHJGEXJAb4mLrokqq8A-txA_KmoQTcj31XzU"
}
}
],
"keyAgreement": [
"did:key:z6LSrzxMVydCourtpA6JLEYupT7ZUQ34hLfQZfRN5H47zLdz#z6LSrzxMVydCourtpA6JLEYupT7ZUQ34hLfQZfRN5H47zLdz"
]
}
}
}

31
go.mod
View File

@@ -1,42 +1,35 @@
module github.com/ucan-wg/go-ucan
go 1.23
go 1.24.4
toolchain go1.24.5
require (
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0
github.com/ipfs/go-cid v0.4.1
github.com/MetaMask/go-did-it v1.0.0-pre1
github.com/avast/retry-go/v4 v4.6.1
github.com/ipfs/go-cid v0.5.0
github.com/ipld/go-ipld-prime v0.21.0
github.com/lestrrat-go/jwx/v2 v2.1.1
github.com/libp2p/go-libp2p v0.36.3
github.com/mr-tron/base58 v1.2.0
github.com/multiformats/go-multibase v0.2.0
github.com/multiformats/go-multicodec v0.9.0
github.com/multiformats/go-multihash v0.2.3
github.com/multiformats/go-varint v0.0.7
github.com/stretchr/testify v1.10.0
golang.org/x/crypto v0.32.0
gotest.tools/v3 v3.5.1
github.com/ucan-wg/go-varsig v1.0.0
golang.org/x/crypto v0.40.0
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/goccy/go-json v0.10.3 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
github.com/lestrrat-go/blackmagic v1.0.2 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/httprc v1.0.6 // indirect
github.com/lestrrat-go/iter v1.0.2 // indirect
github.com/lestrrat-go/option v1.0.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
github.com/minio/sha256-simd v1.0.1 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/multiformats/go-base32 v0.1.0 // indirect
github.com/multiformats/go-base36 v0.2.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/polydawn/refmt v0.89.0 // indirect
github.com/segmentio/asm v1.2.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
golang.org/x/sys v0.29.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
golang.org/x/sys v0.34.0 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.3.0 // indirect

64
go.sum
View File

@@ -1,49 +1,34 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/MetaMask/go-did-it v1.0.0-pre1 h1:NTGAC7z52TwFegEF7c+csUr/6Al1nAo6ValAAxOsjto=
github.com/MetaMask/go-did-it v1.0.0-pre1/go.mod h1:7m9syDnXFTg5GmUEcydpO4Rs3eYT4McFH7vCw5fp3A4=
github.com/avast/retry-go/v4 v4.6.1 h1:VkOLRubHdisGrHnTu89g08aQEWEgRU7LVEop3GbIcMk=
github.com/avast/retry-go/v4 v4.6.1/go.mod h1:V6oF8njAwxJ5gRo1Q7Cxab24xs5NCWZBeaHHBklR8mA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8=
github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s=
github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk=
github.com/ipfs/go-cid v0.5.0 h1:goEKKhaGm0ul11IHA7I6p1GmKz8kEYniqFopaB5Otwg=
github.com/ipfs/go-cid v0.5.0/go.mod h1:0L7vmeNXpQpUS9vt+yEARkJ8rOg43DF3iPgn4GIN0mk=
github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E=
github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k=
github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
github.com/lestrrat-go/httprc v1.0.6 h1:qgmgIRhpvBqexMJjA/PmwSvhNk679oqD1RbovdCGW8k=
github.com/lestrrat-go/httprc v1.0.6/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
github.com/lestrrat-go/jwx/v2 v2.1.1 h1:Y2ltVl8J6izLYFs54BVcpXLv5msSW4o8eXwnzZLI32E=
github.com/lestrrat-go/jwx/v2 v2.1.1/go.mod h1:4LvZg7oxu6Q5VJwn7Mk/UwooNRnTHUpXBj2C4j3HNx0=
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8=
github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg=
github.com/libp2p/go-libp2p v0.36.3 h1:NHz30+G7D8Y8YmznrVZZla0ofVANrvBl2c+oARfMeDQ=
github.com/libp2p/go-libp2p v0.36.3/go.mod h1:4Y5vFyCUiJuluEPmpnKYf6WFx5ViKPUYs/ixe9ANFZ8=
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
@@ -52,8 +37,6 @@ github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aG
github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI=
github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0=
github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4=
github.com/multiformats/go-multiaddr v0.13.0 h1:BCBzs61E3AGHcYYTv8dqRH43ZfyrqM8RXVPT8t13tLQ=
github.com/multiformats/go-multiaddr v0.13.0/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII=
github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g=
github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk=
github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg=
@@ -69,8 +52,6 @@ github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
@@ -78,38 +59,29 @@ github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hg
github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/ucan-wg/go-varsig v1.0.0 h1:Hrc437Zg+B5Eoajg+qZQZI3Q3ocPyjlnp3/Bz9ZnlWw=
github.com/ucan-wg/go-varsig v1.0.0/go.mod h1:Sakln6IPooDPH+ClQ0VvR09TuwUhHcfLqcPiPkMZGh0=
github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ=
github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE=
lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=

View File

@@ -6,6 +6,7 @@ import (
"github.com/ipld/go-ipld-prime"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/ucan-wg/go-ucan/pkg/args"
)

View File

@@ -1,5 +1,7 @@
# Token container
The specification has been promoted to https://github.com/ucan-wg/container.
## Why do I need that?
Some common situation asks to package multiple tokens together:

View File

@@ -1,109 +0,0 @@
# UCAN container Specification v0.1.0
## Editors
* [Michael Muré], [Consensys]
## Authors
* [Michael Muré], [Consensys]
* [Hugo Dias]
## Language
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [BCP 14] when, and only when, they appear in all capitals, as shown here.
# 0 Abstract
[User-Controlled Authorization Network (UCAN)][UCAN] is a trustless, secure, local-first, user-originated authorization and revocation scheme. This document describes a container format for transmitting one or more UCAN tokens as bytes, regardless of the transport.
# 1 Introduction
The UCAN spec itself is transport agnostic. This specification describes how to transfer one or more [UCAN] tokens bundled together, regardless of the transport.
# 2 Container format
## 2.1 Inner structure
UCAN tokens, regardless of their kind ([Delegation], [Invocation], [Revocation], [Promise]) MUST be first signed and serialized into DAG-CBOR bytes according to their respective specification. As the token's CID is not part of the serialized container, any CID returned by this operation is to be ignored.
All the tokens' bytes MUST be assembled in a [CBOR] array. The ordering of tokens in the array MUST NOT matter. This array SHOULD NOT have duplicate entries.
That array is then inserted as the value under the `ctn-v1` string key, in a CBOR map. There MUST NOT be other keys.
For clarity, the CBOR shape is given below:
```json
{
"ctn-v1": [
<token1 bytes>,
<token2 bytes>,
<token3 bytes>,
]
}
```
## 2.2 Serialisation
To serialize the container into bytes, the inner CBOR structure MUST then be serialized into bytes according to the CBOR specification. The resulting bytes MAY be compressed by a supported algorithm, then MAY be encoded with a supported base encoding.
The following compression algorithms are REQUIRED to be supported:
- [GZIP]
The following base encoding combinations are REQUIRED to be supported:
- base64, standard alphabet, padding
- base64, URL alphabet, no padding
The CBOR bytes MUST be prepended by a single byte header to indicate the selection combination of base encoding and compression. This header value MUST be set according to the following table:
| Header as hex | Header as ASCII | Base encoding | Compression |
|---------------|-----------------|-------------------------|----------------|
| 0x40 | @ | raw bytes | no compression |
| 0x42 | B | base64 std padding | no compression |
| 0x43 | C | base64 url (no padding) | no compression |
| 0x4D | M | raw bytes | gzip |
| 0x4F | O | base64 std padding | gzip |
| 0x50 | P | base64 url (no padding) | gzip |
For clarity, the resulting serialisation is in the form of `<header byte><cbor bytes, optionally compressed, optionally encoded>`.
# 3 FAQ
## 3.1 Why not include the UCAN CIDs?
Several attacks are possible if UCAN tokens aren't validated. If CIDs aren't validated, at least two attacks are possible: [privilege escalation] and [cache poisoning], as UCAN delegation proofs depends on a correct hash-linked structure.
By not including the CID in the container, the recipient is forced to hash (and thus validate) the CIDs for each token. If presented with a claimed CID paired with the token bytes, implementers could ignore CID validation, breaking a core part of the proof chain security model. Hash functions are very fast on a couple kilobytes of data so the overhead is still very low. It also significantly reduces the size of the container.
## 3.2 Why compress? Why not always compress?
Compression is a relatively demanding operation. As such, using it is a tradeoff between size on the wire and CPU/memory usage, both when writing and reading a container. The transport itself can make compression worthwhile or not: for example, HTTP/2 and HTTP/3 headers are already compressed, but HTTP/1 headers are not. This being highly contextual, the choice is left to the final implementer.
# 4 Implementation recommendations
## 4.1 Dissociate reader and writer
While it is tempting to write a single implementation to read and write a container, it is RECOMMENDED to separate the implementation into a reader and a writer. The writer can simply accept arbitrary tokens as bytes, while the reader provides a read-only view with convenient access functions.
# 5 Acknowledgments
Many thanks to all the [Fission] team and in particular to [Brooklyn Zelenka] for creating and pushing [UCAN] and other critical pieces like [WNFS], and generally being awesome and supportive people.
<!-- External Links -->
[BCP 14]: https://www.rfc-editor.org/info/bcp14
[Brooklyn Zelenka]: https://github.com/expede
[CBOR]: https://www.rfc-editor.org/rfc/rfc8949.html
[Consensys]: https://consensys.io/
[Delegation]: https://github.com/ucan-wg/delegation/tree/v1_ipld
[Fission]: https://fission.codes
[GZIP]: https://datatracker.ietf.org/doc/html/rfc1952
[Hugo Dias]: https://github.com/hugomrdias
[Invocation]: https://github.com/ucan-wg/invocation
[Michael Muré]: https://github.com/MichaelMure/
[Promise]: https://github.com/ucan-wg/promise/tree/v1-rc1
[Revocation]: https://github.com/ucan-wg/revocation/tree/first-draft
[UCAN]: https://github.com/ucan-wg/spec
[WNFS]: https://github.com/wnfs-wg
[cache poisoning]: https://en.wikipedia.org/wiki/Cache_poisoning
[privilede escalation]: https://en.wikipedia.org/wiki/Privilege_escalation

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
OH4sIAAAAAAAA/5zXa5MU1R3HcXYjIOAVMQZQUQElCGx3n9M3wLhzn8xl3ZnpuSLB0+ecnp6enft9VBJWjSAkxEVXkBUJAgbULTUq4gULlWhQiauilKiFgiaFoIhoCVFIpXY3VXm2s2/g++RTv+7/+bOGi+nZZfauaNOGzkgrmfzUPZ9cOm50aPP2jdPmvbb81I3vbtiTWHDmwAcZZt+W78+6vCU3Irb6u23LjnR37vp07d5Iz7nHX9+96OnXlsw8e9Oaj87agHQnbDradLTpolyhhFG6hXTEW9k5zBxmdh7PYf+CUYlUJZIgc5O0NrcueJOJrDlsLkKXwBnEYlciBgsAWyqFgdnpy6oxPWU3SCpQE0L+KI9xiugtWibToqI8ptXsJL2rZRtOFAr/3yxqAQfJqG6iS6561FqQsk7ZkecUt9cac9WSpOSGJb9d9njNsIqzmY4lt2HU0YHnLFh4G/qVNqeMOkq0GRdK6vCzJEWL6CFdALzMsQIyEAZUYjlW0nRJJAwPNN5QBY3lAAC8oKuYUsLKqqFRAau8RgGl6UwaU891vofXTUn5Lu58ZDzpRzqlf63e713VHbzpqg8X3iqFfzniqfGtdlx7DrzQfPbDT2RXHLnnX9e/fLJp/eFR27974d9/3HHJyusXt7+Zcoyd9uIPSzePGAZSho/biynJrhC3JrEIFeSUkOc9rmSbwWqlMKl5Wc2d5kRUz1iGjOTLxLwatBZVv9tdkWFIoylbDvjsjjbOXSt7JFhkXVQgBS5ZagSpgewAEkcYqFHAGSojIEJEyCNdFjmMoUoNBjEyIBJhNR0JjEQIkQ1WhiJCSMBkAMl427RzzztvjD8G9jP9SONm9dxw6dFNH78+uqfpgtRV3ZEfJ3jfbfvkw0MLr/J2r205cGjrvOVvdNaa4tPO7GpfMWXU12+8N4ELOK/tu2DJzrc7rztnGEglu0VM521lPl0LmqOuhBRMZ/KC1ahYRXdSUax5bM9nqlRtJ5nKUJFyLjtvMoMyF0yaCvlE0mGLI1MkAKGlFOAEEiaKOx0qUls4YKo3gNRIdgBJpIwIJcgaUCaaJmkaILosaAQLEm8IkgiIpAmY0xECDFUhNhCUiCxzGGgDSIuv+WnPyHPyh1f3XRDuR/p2VXRu29o7XKfEVTN6F/kfv2XLyyfI7vWT+27+NvDZoZk3L7jm+Jm3Os9qPbjd0/fNHdmtTcKnnfKMpnVLf977PTjw2djhfO7CAQLNKFVS89GU325j0/ZcO0ybc+4QnyhhUfTasSoVK1aHxxgqklZIB+yYOjhUZWvRrNNVjqlK1iFUTTZTwFOLpMopW6ZYyeZ03t8AUiPZwSVJjIoAgwxNBSzlOVVWdaRJVOAwMgQKMKQSFXmdcARSEUkGFVUWS4IApAGkhyb+bPHD1yg3jHt1m9KP1D7Z81H2oxu/WEaZY5NOPtrT8fQGafFXc2/7HNw+4q5/2vnn9yJ2zIQFm8907niQ+eKbg9Gde73li/RJnv3dpmV/rY8cBpKRC1lNpmBBL/uSFVd7RkplEuFSOJRzJ4rZTCwlxnRLu9RWZKNCdqhImbBIY6Ag2CxqWrbFcrYsiXj8SibSHpDEWtRjCmeor8x6VL8oNYDUSHZwSVDGEuVYQxR5ATAaAZqu8ghSGQGDhRLAgOVkrGPK8xLPA0OgqkqoIKqDS1o/ZdHt7ldffNPyt3un9yPN+MU73vKTuw8F1z17+fe+51Yefn+s5+rz1t0Fn36m9akHz7viifvOXV1r//KVWRvbn22euGD9LPjK3d0FX2zTe4vgyMuOjRsGkibmcKCuhMPhesxQirLVAkvAEtUDvmilYI5EjIALAIGIfCwcHfKSUgVH0JZJKW2yFpFs2GKEzdlstaLkk0otmw6l7YYt68rURDGXa2RJDWQHkJj/fus4jTeoTCiUACMLOsuyLIepZlABUchCIEm6jCmLeYE3VKgyPOE1QR1Amsif2hd9xD//84nTf92PVDgynzy//f4Pbthd2fXV6dZXxl7bd1oYX7LN61o7f/TyS0bfd2Tes4ww76Y9S5ofK+y7+bONZ59/ZzI/6qLN+49dvX7mlObhHA5Wtz9ZTHJVZ8hU8lS5rN+XUarhUpuiQFeUr+QqcrBsWKyBSMQ0VKR4oEYdqbqYj8slrlyzSL6YyezWqZoTSDgcr5hqCleL1jTBldUbQGokO4gkEkGDCBuiJsssAJKGdEEVMRUhMVRKOVZlBRHoIoZAZBneIAyrchpiODyA9OBLv5tv77LPvqK+98p+pMyOH1b2jFrW+vfukx1XjlkxsnjnNPWdW3t63dHO5nMegCO37Np74uSkNZ7I0i1be0949RWt5y/v/P29k17auiZ0r/PCYS0pqoZ8ArZhD1EVn+IuakF/LOV3hi1WSYmgSDEfzJjSrhCXrg75BE9mcEGwu4uGWrRWg1az3aaLDo56QnWTJeJ3pKqRUnsorNkKXgQaQGokO4DEU5lqiFCDZ6jGMzIiSBcow/EaRw3IExYQwkFGxwKHJIGTDBkwGtIAwoMn+CfL7+77urfL/UxtwS39SH+6sGvR/M3b7j489vTU1OwxHxxnp7rWHVx98fpL9ph/M/fEq1ue+e1N/xDGNz9xCzw8q3vyZT2jp46ePuP9mZvqo/bv+6llOP+kuMfscECbC5eddZJTfHlT2M5bk4GEYvWZS3mxElTCKdkUS8XjcMjXHUtLCaermiY4S2g8zpoiRqIcssplwuUlECoqeiXutikRACONXHcNZAeXpKqCqMmcgURW1lgsAUkHkGUxo6kGhYSIEksg0mXACEjloAGhCmRVZoXBJS2LGo9+PG7/LrnvXXc/0iOu5JnKZS0/9n65Za8n+d3jdfGtx5ZEVtktu9uPT1+9Z8J2T8fGrulTS5mltvn3H+xyHljjfODJHWt3LkycGfOYDYwaBlLF7ra4goKzXg2zyJXysnwlTKS8I2su5R12iiqkXKon4gb0ytyQ30nBONtWymUrZU/cUi9DLppTvJZglavadJxyF5N2wSSBkDNiVWONvJMayP5vSURSkcAYLBYBx0CEVF0SoarxSDQIzyFGRZJMdY2DHBEk2ZA5RmU4BjBwAOlopu2+lb0heeXJP9zxnwAAAP//V8QWnXsQAAA=

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
PH4sIAAAAAAAA_5zW65MU1f3HcS7-hB8igpfIgqUxCqLC0tfTfUADMzs7M87ObubaOzMEsM-lp6eb6Zmee49GvEKwVBQRgygIUVHLCwoqoJAAikCQaJRICCqFGPCCcXVFoaBMJbukKs929h94P3nV-ZzvSg2XrEkV9u7kwFW3J6bv7bj7tflfrjm4e8_grc7Dke4jPx6c_Mm87olH_O9Of35_59-X7z2xe056dKx7156F074aOXzCcemCRe-Y4T3n3v7SNV-fdd4qVfcLA48NPDbwArtYxqo1mcxJT2ebmWZmUgE3s09jtUxqMsmQKSZ1ptRBu5lF0WK75ZbawpVO25NW2rLtfgG5XFZKtlwBr1GPVfyKU9YjZS_BOEv0yVouNxmpBUxr-TH6osmv4Uyx-L9NM5PUWqLtmqTohbQnkWp1i5JlxiOWLxAFAdaJeU13Z0gwWsN2AOdzc267A6tz5uDmGTPvUH-pNVfUOWU6CBfLqP9ZkqUl9fc6w3KqRmTVUDWGB1BiiKoDCBhJptRABAuCxrJY0zHPQBZjbLCY8hKCVBOplbMwDXbdsO9O4ZT5m20fTPywBymh3HfTBjDl5MzlT65xpm15kC4-f_2hlTtKyQUbrj78wBPfjn1e3T9i7OmuEfmt25d4z_q2K_0H36lRiw_9NbK0Szy0d3A_kPKuFk6qOYqVTSCj2uGNknxdT0BN0Etlqklxr8QaSqzF468oQl-R0oo7rztKQaK5crqzmMq7vOV4uh4jFZ2zPIrfFL0hS_ZYOFikDSA1ku1FAqJEZIRUA2gMy0OeY4EOKGVlHmCDIgZKKhYhp2NKGQR5YvBYZAWVp4j0Io1b4N905xU_e_SJj1-4pAfpbefa207fnMit_9XP39xxw7D3Fk0bH7vs09W_3uwcG3Vk5Nxv14yYP2Zj7lLPQ01Nnw0bsmXTssuZprL6-dX3zB3U9NH9q8_tB1KhgwUG8gA54HH5OcMyW1vqjmLnO11GNB0Ph6ut8WI1zAbdSMv2FclKhWK2riCS9trFvDvmd3tC0bpo8SAeC5QExZfiO3LeIOuKePkGkBrJnkEiWJYlnjEg1nhERSKouowIUgEvGUTGRBN5Ims6QiyVZVUwNIp4GUNOxr1I199x4OH_y6103Q-3DOhBuhYw1x1Y9eHYjejREfahp2Z9SNaqo83Xb0yff-mFr3_srFg7at3FV2aEy28atv2p8zbc-313YOQ3y65gm1Z9MHzdipHm0H4gFYmaLrQGWjpFLp4ICmagamWKHI560tlAsoa1uNcotoQKWj7fGuvz3Ck1v5hJgvZQJGYIKTlcFrypWocVLHPuEC_oWa2e0M3OVsen-BuZuwayZ-YOckQARDJ4TLAsChqUdVHVOBkA1pA5GVKGkaiqA04CDISiIcoUMhRjCHuRmjJraxO7f_ji-PiTE3pf0g83F4Zc-hF4-7uTV4XPG7xw986TC__2_qlnjrf9OLDrrKfeXioPGvtN0-NHRv8OHh7_5fzP1V3Lt40Zar-z-c3Vtx5O54b0AykTCrGsVS1iKmkdapQ1q6lqKWkV2gD1J3MIY09SlHw5O6yHgn1FqnoTLU66YobsbASoKq46rmoka2c8LomNkHBFYH2VVldNa-GTQgNIjWR7kTiVAIYRsYEFTcMCgpDqogw4TFXGwKqmYaACRtMJ4ClmEDAQFaHAYAbSXqRXxt9z8fIVxXOXjpjI9SDtXIkK6MJ3T6xbv-WuN7azi9K8UGl5a1t056x9G6fgxJJ5g03lSBk_O2juXV0Lnh2kVHfIwcqrKw-9dboId5X-eU5__iRPLhyxMsF03C9ZnWYKtRfZajIbUDjb68k7XFG2UL5adKesKOwrku42qkgrRaK2lI1jYJaMelnpaLf9RhW0sfmUrjk-FymaAcHBDSA1ku1FYjVeBBpGBqUCpjIUKdI5TuAwwqqhiQAAyvAQ6BoDBCgiwSCizMsSQhzfi_SP-2K_-PGE9saxTzMze5Dy-z0P7Di679olRys3fzdIXbZgbpvy0Krm5oXnnP_1w9yzj0yF8_64bCjzW2H22feEv48NLk6_8UD32fWPNvlf_CS18OUB_UDSE1WcaNUKSsqx_SjA-zNeLYI4T0cybfM4pbMg4AknnbbOetjqK1K-blcKUt4DWcNrVBzBIiJ2fGE7W8gCKZbI4WhBy4KkP9MWhA0gNZL9LxJLVMQhA_KEkTAjEkbnBZFILMQGQRLPi5gSpAOqEShqqoFFWZA4jCHoRRLeO9XcMqtwy7p35cd6kIY99snirRBtnvqcHN9benz4hCuG3LJt9bafZki7thTP_mHpi5PGXfbY6N1Nm68Z992tLD51S-q5DR98dsnhAbNSNzwZvOr_-4FUTdpy0XIjlg0nZSHkqaneUBVUCylgZEtmwQ3LhZrhR3WtkrX7PHegSpISVKtKuCYFyu11s5pK6FHbR112BNtsIZUOt1fSHVIuLzYydw1kz8ydoGqUF4nBizIHZYFyog5ZLHCU0QwEOZGROVEiusr824blDCgBSSIMgGdO8ClPP7KYPJnsQIeKG3uQrnz5teFvvD98hrrOc3nrmK3rn9s_-09PjBzaddOwxDl3Hz1xfEx810uPhvYcbL3sL9dNWjnuxamjXnCFEheAP29i5nXf3tGf6y7r6qwrJZfHlLyGLCvuWCf05Qp6JGDYBaNWqnvS5bKN_VRBVaWvSDnJBG4lHBEAl05yIccVIHZabmmLBttdobSjaKY3FRY9alvY42oAqZFsL5KKCAaEQkMlokgpyzKijhlRpaIoGZClCLCU1ahOIGQhFWSDQwLLqkhlzrwkvOH-ScEtSw68Omr87B6kpYWRa185WbvuC8u8aMC0i1pXbHeO72P9982fsHhh2xbf8WGe0y5Zq-wAk3YenZ05evG93MzVAx78aXJlxr1r2hce7A9Srqh6jIIVjNU7INENUg7Tqmz7tFBb2pfy-oq6zxuOOO0kWo27-3yC58tCwi900DxOtpk-k2txFCfuCGKllnOscqVk-W0N1dmoFcw3coI3kO1FElVWYhiiGhzgCS-xPES6zFKVAZxgyIAXJZWjAOsygppAEG_8Z-wIQZzai7Ri5eyp3V8981nL9fET_woAAP__svLMp3sQAAA

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,21 @@
package containertest
import _ "embed"
//go:embed Base64StdPadding
var Base64StdPadding string
//go:embed Base64StdPaddingGzipped
var Base64StdPaddingGzipped string
//go:embed Base64URL
var Base64URL string
//go:embed Base64URLGzipped
var Base64URLGzipped string
//go:embed Bytes
var Bytes []byte
//go:embed BytesGzipped
var BytesGzipped []byte

View File

@@ -21,7 +21,12 @@ var ErrNotFound = fmt.Errorf("not found")
var ErrMultipleInvocations = fmt.Errorf("multiple invocations")
// Reader is a token container reader. It exposes the tokens conveniently decoded.
type Reader map[cid.Cid]token.Token
type Reader map[cid.Cid]bundle
type bundle struct {
sealed []byte
token token.Token
}
// FromBytes decodes a container from a []byte
func FromBytes(data []byte) (Reader, error) {
@@ -92,11 +97,36 @@ func FromReader(r io.Reader) (Reader, error) {
// GetToken returns an arbitrary decoded token, from its CID.
// If not found, ErrNotFound is returned.
func (ctn Reader) GetToken(cid cid.Cid) (token.Token, error) {
tkn, ok := ctn[cid]
bndl, ok := ctn[cid]
if !ok {
return nil, ErrNotFound
}
return tkn, nil
return bndl.token, nil
}
// GetSealed returns an arbitrary sealed token, from its CID.
// If not found, ErrNotFound is returned.
func (ctn Reader) GetSealed(cid cid.Cid) ([]byte, error) {
bndl, ok := ctn[cid]
if !ok {
return nil, ErrNotFound
}
return bndl.sealed, nil
}
// GetAllTokens return all the tokens in the container.
func (ctn Reader) GetAllTokens() iter.Seq[token.Bundle] {
return func(yield func(token.Bundle) bool) {
for c, bndl := range ctn {
if !yield(token.Bundle{
Cid: c,
Decoded: bndl.token,
Sealed: bndl.sealed,
}) {
return
}
}
}
}
// GetDelegation is the same as GetToken but only return a delegation.Token, with the right type.
@@ -112,12 +142,33 @@ func (ctn Reader) GetDelegation(cid cid.Cid) (*delegation.Token, error) {
return nil, delegation.ErrDelegationNotFound
}
// GetDelegationBundle is the same as GetToken but only return a delegation.Bundle, with the right type.
// If not found, delegation.ErrDelegationNotFound is returned.
func (ctn Reader) GetDelegationBundle(cid cid.Cid) (*delegation.Bundle, error) {
bndl, ok := ctn[cid]
if !ok {
return nil, delegation.ErrDelegationNotFound
}
if tkn, ok := bndl.token.(*delegation.Token); ok {
return &delegation.Bundle{
Cid: cid,
Decoded: tkn,
Sealed: bndl.sealed,
}, nil
}
return nil, delegation.ErrDelegationNotFound
}
// GetAllDelegations returns all the delegation.Token in the container.
func (ctn Reader) GetAllDelegations() iter.Seq2[cid.Cid, *delegation.Token] {
return func(yield func(cid.Cid, *delegation.Token) bool) {
for c, t := range ctn {
if t, ok := t.(*delegation.Token); ok {
if !yield(c, t) {
func (ctn Reader) GetAllDelegations() iter.Seq[*delegation.Bundle] {
return func(yield func(*delegation.Bundle) bool) {
for c, bndl := range ctn {
if t, ok := bndl.token.(*delegation.Token); ok {
if !yield(&delegation.Bundle{
Cid: c,
Decoded: t,
Sealed: bndl.sealed,
}) {
return
}
}
@@ -130,8 +181,8 @@ func (ctn Reader) GetAllDelegations() iter.Seq2[cid.Cid, *delegation.Token] {
// If more than one invocation exists, ErrMultipleInvocations is returned.
func (ctn Reader) GetInvocation() (*invocation.Token, error) {
var res *invocation.Token
for _, t := range ctn {
if inv, ok := t.(*invocation.Token); ok {
for _, bndl := range ctn {
if inv, ok := bndl.token.(*invocation.Token); ok {
if res != nil {
return nil, ErrMultipleInvocations
}
@@ -145,11 +196,15 @@ func (ctn Reader) GetInvocation() (*invocation.Token, error) {
}
// GetAllInvocations returns all the invocation.Token in the container.
func (ctn Reader) GetAllInvocations() iter.Seq2[cid.Cid, *invocation.Token] {
return func(yield func(cid.Cid, *invocation.Token) bool) {
for c, t := range ctn {
if t, ok := t.(*invocation.Token); ok {
if !yield(c, t) {
func (ctn Reader) GetAllInvocations() iter.Seq[invocation.Bundle] {
return func(yield func(invocation.Bundle) bool) {
for c, bndl := range ctn {
if t, ok := bndl.token.(*invocation.Token); ok {
if !yield(invocation.Bundle{
Cid: c,
Decoded: t,
Sealed: bndl.sealed,
}) {
return
}
}
@@ -162,6 +217,19 @@ func (ctn Reader) addToken(data []byte) error {
if err != nil {
return err
}
ctn[c] = tkn
ctn[c] = bundle{
sealed: data,
token: tkn,
}
return nil
}
// ToWriter convert a container Reader into a Writer.
// Most likely, you only want to use this in tests for convenience.
func (ctn Reader) ToWriter() Writer {
writer := NewWriter()
for _, bndl := range ctn {
writer.AddSealed(bndl.sealed)
}
return writer
}

View File

@@ -9,11 +9,12 @@ import (
"testing"
"time"
"github.com/MetaMask/go-did-it"
"github.com/MetaMask/go-did-it/controller/did-key"
"github.com/MetaMask/go-did-it/crypto/ed25519"
"github.com/ipfs/go-cid"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/stretchr/testify/require"
"github.com/ucan-wg/go-ucan/did"
"github.com/ucan-wg/go-ucan/pkg/command"
"github.com/ucan-wg/go-ucan/pkg/policy"
"github.com/ucan-wg/go-ucan/pkg/policy/literal"
@@ -36,7 +37,7 @@ func TestContainerRoundTrip(t *testing.T) {
{"Base64StdPaddingGzippedWriter", headerBase64StdPaddingGzip, Writer.ToBase64StdPaddingGzippedWriter},
{"Base64URL", headerBase64URL, Writer.ToBase64URL},
{"Base64URLWriter", headerBase64URL, Writer.ToBase64URLWriter},
{"Base64URLGzip", headerBase64URLGzip, Writer.ToBase64URLGzip},
{"Base64URLGzipped", headerBase64URLGzip, Writer.ToBase64URLGzipped},
{"Base64URLGzipWriter", headerBase64URLGzip, Writer.ToBase64URLGzipWriter},
} {
t.Run(tc.name, func(t *testing.T) {
@@ -172,15 +173,12 @@ func BenchmarkContainerSerialisation(b *testing.B) {
}
}
func randDID() (crypto.PrivKey, did.DID) {
privKey, _, err := crypto.GenerateEd25519Key(rand.Reader)
if err != nil {
panic(err)
}
d, err := did.FromPrivKey(privKey)
func randDID() (ed25519.PrivateKey, did.DID) {
_, privKey, err := ed25519.GenerateKeyPair()
if err != nil {
panic(err)
}
d := didkeyctl.FromPrivateKey(privKey)
return privKey, d
}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
OH4sIAAAAAAAA/5zX+ZOUxR3HcY7FwhKToFJGFAU1ghzL8/RztpxzrzsHszuzcy1Ru5/unmd6dubZnXsGE9EtFVnFSCiNEFfFiCSKqIVI8ECBKGiJiMSTFdCYeGDK6GpMWcSUtUOq8ts++Qfev7zq+6nu+5lRys+riKuTYwdvSCw9NrDty6c/Wf668n73nFsqQ988uh1Z8rTNu9X6hkO33S/vG1i92+//ontN6/BubU54fntiUnXqrPNfo9p5bnTWd3PP3IhMt/z52L5i2UD5+aQnvVRsFVqFeQWjVdxsoDKp6SRDrsjS+hUNNZjNtFdJsa1CzUwCxSK8imjO7curtFHwBqy8US3hlBT08XQlkWeGkSPmfGZZ8zEqGLTWOzX9yyemGZli8X+b1XAxESdxALIVX6E3xkiY1coeswLDMOp1BVRgOrGnqxEtukoJo9fqub7fQD09Rmv3z/vRYtZaQT1lOs4olvH/nyU5WkIPmEAQkAYg5lhDqigxjeimJoqEMgC4JipMViURiCYTBQHLBHGZCkyRNcgYzVt5gwauDa67+uiirx+KuQZnjgB9/2H3noUzrj79rQdv27HpuSufnOrfvu3Myf98rfv5Tfds2OX9de9w92Mfm/m9s2eOe/etzPnd/1jdeqI8vvuVbYOb8Q2Ltky0CZRDlAfcJKqHGSklXclQxR+mPKbgcM5n5awkRYmwM2SltSQqjRYo3RFD/lDOnW/TYrxd7ayVQaQme10dVl3RPCardrQHkFJUvTUT2QCyk20CaQpUFF1CnFJJpDqVoGYSDKhuMJVDlaoqpIIMTIZVhcoMcCYAnSgC1GkT6BF9x2d9X19nTBw/+cgI0KO+/W+sk4cmDz7/7AM7D7s2+BdIFw0vGLv9yzm7Vv3h1QN/WZHwxy9Qj0evv2ftkX891BLy7V2cWjY+sGV9f+zYHh4eYxOoXE8E3BFPNB+q0Kw7XexLpfXeXiPrd5WC3N0Wj7iBFfeQMqi06aMFKtcMf9wRrbN4EKOa7KxYfRkQ0/3ecJ/LV/dnkl2OgEPSvIViNmQDyE62CSRDgWEBilwECpWwADVsKkQnhgQZ13QZMVWVITGRCLCmI8ANCWuiSiSqNIF+ExuqnnSds6b7zv4XRoDWzN08c6H1GByE86wXj+561L/q9pc+G1jy4/ya71uPb3kXLJmwe/jlHFu3+NhFK2/8Sce4sZtiLQezq/uVBx6OXnv3n0+zC+T1F5MuENTKFW8u0ld3GcVQNl0gZodSiCk01UkMV9SVauRNXR0tEOtkic5YKtXlDgKt4VFKuhWoGiku417g6wuUimZ7DbTJDAGv2waQnWwTCIka0XVJ4JCKVJGQLGqmIamaYaiQKwpVIFQMgZgUCQLSicqxTKCuyxLATaD4JZf/4mhvbf19y15uGwFyrodHo9vOP7kzObhklvuTfQ/j3IQLn5nz6dKNn0xo7H/nkQs+HT70VvLwmWzvm3c/Ofn7g3f91jvkb7/5vpWHHl8EX3/B7sSxiq9R5bkIsAJKJurhPj9z1GgDh3gy18ViyOP2sa5oUso4C9aoJ84fq/fKKm3LtRe8gWTe568V8z7sMCU1FnA7gJnOhXq9Lk+XaHTamTgb2SaQQIFEEaJcgLIqQEEQgaloGsKIMs5ESRYFQVYlU2UEEVnEXCUSA0zTBLUJJM/nb351ecu/h6dLlREg67y3b3be96Ky/p7L7jzeO9s5Y9Ka5fNxZHc8cVC6+K83iXPfO/GjL5ybrbZrWq4QPu64rfu7adMP7v/uyt/f0r7yJjBpkk2gvgQPOTusdDGqhOuKNxROw0ba29lFUjCbqNV1MSDWZZxgViRkjBbI8jUa1aKl0Y42qz3sTVt11dQSeo5WqsGKD1NY0sN6QS8aUhXaALKTPQWEFU0nKuMi0aGCDayoJjIwZjrGHMoEAUI1QTINxUAShCo3DCwTWdOZ0QRaAhdf1yIf7unm5atGgObsH8rs5FO2wH1r/zb84c8WrNLL179/za+G51WvkvaKXjguP3XmXWetHTix59zd32Te9h2ftGTbhU/dv3PvjcvAlBnjzrAJVOjMUKhKznS4jZR10ZWMVz1JZ5zWHbmuSqnglzpSMqPVuiPgkkcL1Butd1DQVQmGgByp0S5Xo5SLKXlfvD1QDolQZ2oxXIwFk42AUrEBZCfbBBJlSZFFReIIQZlqhgR1U0MSlilROBAMTACBAjYZMyjUich1w1B+2Dd4auIOnLPCY3wFNzxIc+tGgKqX5an27Qtn37C2d+ykS7XPnz30TSi9onDd2eeMK7N4/6x78XLQMnnlm6/mFlbIeRee9qWybfCjBceSi6YVdg2s7ZxgE6ga7sp29QGTJ+LOWAooJcsXJ9loQgvFmZOXOgNt7nox1jBRyAVGC8SNbK0zCyKmrDsDRrrhShLqqGQ1DKJyJVMvknY/jNV52hQbThtAdrJNIIgVSdBljUuCwCSgMxGbBhENJBLIBWYgAzCsAZNAwdAFXeZMVVX4wywKTaBZTxz9E9y6b0JPgu8YAZo9A258I6l75KfJM2Omb+T3zjDPTW393SUXnHjswB3DY05a7wQ7ux9fXjtjx4QxS6fPfmns3598sWf9lkvB83sOXrxytt1XXK5IHCHk1Tx6sc0fTPdlCjTBYmWHHNH8XR2s3khVjKqeFD085R71BeXrdVytWKqSqCaDMiehTm/Q4jCVrUcdrBKTOfR4vEGto01N2bkgG9lTF6RBwFQicAqJALGiaropCwggCWMuAyJThAxETUIA0CVV57qkUEVlOtSbQGMGJuaOTFzyx/FHjj81AvTqwIExd3vB9FuXrdHmrp7106G33/vgo9tP3zjF8t5ZOLz52q2bjt1x6+yTH6zQbmGpiasOJ5Xw+oU7n3v8YMuH77Vs/bbF7kcVmjBmuhuhVMyVUNWiSXg9XMs2yvUkpCnma8BKxlK0eqXT8o0WqBgpmI5YKuLvyLiUeqTsp42S6qiasUCjlFG9Xk1pr3ujpN0BLWoDyE62CSRpMtBFTeaipKqYyZJKTEwURGWkcVHAWDcY0TSTYipjjFUu6YL6w2P8v0AnP45M2du/fWgHeOWD/wQAAP//IuQ6Y1MQAAA=

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
PH4sIAAAAAAAA_5zWa5cUxR3HcVcRiejmuCII3siKwgnubnd1dVW1eIS5rzM9w8zs3HZETFd19_T07PTcZ2cH1KMgoB41YgIo3nM0G1GCRhCRiILIEaIhIEo0Bi9c9ewaFfEazYMd8iCPdvIGvk8-p_71e1RnZaujyt_e2_LQLYk5Fbb1QefFR9-_5LzWO59-9PfWoWV_nN_f177z06eH31j13Je8-Wpk35bTccKjtV_22MRfnz9DufuSg8Ntn02KzZtw83sLxj-mGE441FIoVZhidal9qTl8J9fJdRRZJz_IlIpaI2pavTKjDVxZR_5MQXa4aFIFgr-gMCrrOTWUqWNajNZERzin0GLRz7IxsTcfAgnGsqrRpedyXVQpMq2Wn5K68dmLWLpU-p9msRbQ-usuHEsGorZK0BbwxWzxvCdrhDK2vL23UMCRTM0RlStVxPK5vpsXMaWvj3Vee90i5Wq9s6r0VbRTWalC__-smtXKyu8MERNOwJSZkCACeAFgzkC6xGkYAhOLqkJEiBXJkJAuCUBUTMIA4KEgAEWzchbT5DXHfxwc7LiqNnPmRwdHgBa8NO6jDQ9uvW6wa7DHYetfP3DxO4s7JhybLa1YcerUV-Yae7aDww_P2_zjvH9euWqOOW3yjBWtO2__bKzLvfnR_enEpmaBMtFuy4qEsgrlqRMpPm86mql6apjI4V63V_bFgl5WT-USpQhDowVK2amiFmM8tEUsiRJcCeowHM9AvVQreLGE83LMkcBBI99dAE0ANZNtAGFewJjwkilBJPG8TphoKEQhmihKpsgBXuIVhXEGRRQpRGAmhzkRqIpOaQNo4afuoTWTj60cfjw5fQQoxy98ZPGmF3YsWLJo8voJ587Y9-X38geyLBq_nHXZIy9fPun5m1pebqVzv7J-NuaM08XEzYl3v3kmtfuCr2Yc-VAa3vtxS7NAnpKSKsBEzVaMphWdFB0kgNSEgHpwiPe7a0qaxYtVG_SVq_7RAhkey-asYmfUZ1XKMbGSr-Vo1UZ60rZyNV6Uy8l8MY_iES1ic0abAGom2wCCEqcLVFRNpEKBaghAaCBJUYgKOVNVGMQCUyXRQBqFTJWwKQkIIoZFQW8AvZV64bRDez_6flYbbmu8oDa_euu2yJB9w1vX3uO-YrZvobj2yK07V7-1YebjrRcgbsvS4fiyJ9_gpx4KvT5n_A7PTz-cqF_asuuaoTFnn2N-bbU2CaSHi0bJlrEi3kyh6NFrgqOu59VKOJ2t9Xj4sllT4wXqJdFQfzI2aiBvIGSG_Zls2IsDSdKblRV3QlQz2X7Z2evudVBk16QIM1yiCZsBaiLbAOIEnROQppu8AjgKiKqIhgQVwDQCTCKJkqCIBIqGpoicCilvcoxDWJewcPLE3TD0fHzb0y_BrtRd2gjQN3fd--36ju_CYzuV8adcsOeA95UvVv-09N1t05_bN7DllouWTN-18r4nTm-9Y8uZ2L02fj1XLizHlzyfrZ-x65Pt503b0uyJs0oDhpWuSh4vwFpJjlcDciKRCbtQTzmvxkWrKIWCUQm51FomO1ogKyMLyXSPx0xHxKrixwFT7a9XgzUUTuedXgDi8XKmgGJmJOwMNQHUTLYBhERGkE6YCTXEYYAYxxuE5xGnCbopAkWjAtCgbhCMKAUQmQqkvA4wJaQBpNyhPfDyK9Ijs-yOv40ArTv_hoMtSbB12NjtzD1Ef35ow47k_D3frn41f-2LX6YmdTxzzba3t180_7XFV5m-fz304tj2Td-t7Nx_oblszv7ctI2Hmz1xhayl1myOkhEOxUt2S_S4shFvMI7dIbseyPa4AlalJ8q6g2KhGBktUJGVfQEaSsXtsK7EnXnC6zIP84ZHrYUyGR9vcxXj9lwuaIvG7E0ANZM9-QcBHkNCNFMFEKhYFTRiSBoUOV0RTE3DKmWMCJKhijzgeJWakgoIwyLUuAZQSlq-Y177mBOSHt49AjRF-PBAe9d1H3ffcvyZczrHLAhP9X3jC5y797YFa-mNxYl_evDqo4fu_8NZh3d88un1R1f_5cfBf8_76p3tv_psyooll_k-nj2mWaC6b8BCmVrCytYjIFZKF1wytmUFKdijVuoCLIdrBV8dk3AxbIwWqJRAkpyRMnkY9ReLcipX8PR3u6RcrheykFINGCCc7-lJ25LMpjUB1Ez25IljDHFYpCYUiUYR4yVkUMKYIEiSiTDBSFcRgAajPAOU6ibjmShBToOwAXRf-6V31zceuXHdjHV9I0D7Jn7wgXzr4TVX_-PYw_mpLatO69_qW7R1Q-m8o9OcsGP2rM_f3lM_3n0_-aL18zWHV-eHzkik9r4_LriMt16a98Tm889sdiTASDqRwFLW3evj6_mU6i96cqInGEY4Ea0F1brlsPUXJSlCrcpogfRCzGll1YKRsqXrWEuVajq21wK5buKv5FxOV7wQy4Wz5Wwg3NRIaCbbABKopoi6BkymSSrTRCpSQ8UqEEQBmkTTBQp0VcSGBgAvYaiZCgQMUiz89wXdVtm7cNtjqvLmb5ZtHAHq2vfX9Uem2q-ZXTzw3oub0ruemj52f29hwuWeZ2_6_qylidcO5d9p3310-_wptTV3Dv1WXZzbuLsNDU2-dzDy7Sf84MxxTQKZAxWi5wO0Agci0WTOnStHklUpbPaHSi7JcsV9UbvH6_IHzHTVNeqRwLtlj6rV_T3ZehxGex2KLA3EXX4XhNmaGZdj-VjCRgy37HA4mhkJTWQbQBImhOkcbyIeQA1oiOcNBVBEdBWYlOc0IgBAREPnBYoABSavUAI0RhFuAM22T_nzs8NTTyz94YFVI0Bze_9-4utz3dvfW5B7fXL7uJWvr-1rO-uG5evusY_jlk-ynvzheOfE5IFIt4ieunAfO3bK-CWuX2w-0HbQP_fDi-8Y2NPsitNYLCfr2YLGEhrwg7LNoL3ZWKLSAzwDxNvNV_OA1L0oFVdToz5xuURswBupyoo7Ggua8Vg8kIjV5TLvcyCUDJsV7PXKuglTehn5mwBqJnvyBSEd6qpKTV5HCEOeU4mBCJSwpImmIkBd4BRGoUEUHUlMQ6amQVVVJB2CBpBwxRsH-9-cvnYnOfvd_wQAAP__hMJ751MQAAA

Binary file not shown.

View File

@@ -3,6 +3,7 @@ package container
import (
"bytes"
"io"
"slices"
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/codec/cbor"
@@ -73,12 +74,12 @@ func (ctn Writer) ToBase64URLWriter(w io.Writer) error {
return ctn.toWriter(headerBase64URL, w)
}
// ToBase64URL encode the container into pre-gzipped base64 string, with URL-safe encoding and no padding.
func (ctn Writer) ToBase64URLGzip() (string, error) {
// ToBase64URLGzipped encode the container into pre-gzipped base64 string, with URL-safe encoding and no padding.
func (ctn Writer) ToBase64URLGzipped() (string, error) {
return ctn.toString(headerBase64URLGzip)
}
// ToBase64URLWriter is the same as ToBase64URL, but with an io.Writer.
// ToBase64URLGzipWriter is the same as ToBase64URL, but with an io.Writer.
func (ctn Writer) ToBase64URLGzipWriter(w io.Writer) error {
return ctn.toWriter(headerBase64URLGzip, w)
}
@@ -109,8 +110,13 @@ func (ctn Writer) toWriter(header header, w io.Writer) (err error) {
}()
node, err := qp.BuildMap(basicnode.Prototype.Any, 1, func(ma datamodel.MapAssembler) {
qp.MapEntry(ma, containerVersionTag, qp.List(int64(len(ctn)), func(la datamodel.ListAssembler) {
for data, _ := range ctn {
qp.ListEntry(la, qp.Bytes([]byte(data)))
tokens := make([][]byte, 0, len(ctn))
for data := range ctn {
tokens = append(tokens, []byte(data))
}
slices.SortFunc(tokens, bytes.Compare)
for _, data := range tokens {
qp.ListEntry(la, qp.Bytes(data))
}
}))
})
@@ -120,3 +126,20 @@ func (ctn Writer) toWriter(header header, w io.Writer) (err error) {
return ipld.EncodeStreaming(encoder, node, cbor.Encode)
}
// ToReader convert a container Writer into a Reader.
// Most likely, you only want to use this in tests for convenience.
// This is not optimized and can panic.
func (ctn Writer) ToReader() Reader {
data, err := ctn.ToBytes()
if err != nil {
panic(err)
}
reader, err := FromBytes(data)
if err != nil {
panic(err)
}
return reader
}

View File

@@ -1,14 +1,11 @@
package policy
import (
"fmt"
"testing"
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/codec/dagjson"
"github.com/stretchr/testify/require"
"github.com/ucan-wg/go-ucan/pkg/policy/literal"
)
func TestIpldRoundTrip(t *testing.T) {
@@ -65,19 +62,3 @@ func TestIpldRoundTrip(t *testing.T) {
require.JSONEq(t, tc.dagJsonStr, string(wroteAsDagJson))
}
}
func TestFoo(t *testing.T) {
fmt.Println(MustConstruct(
And(
Equal(".foo1", literal.String(".bar1")),
NotEqual(".foo2", literal.String(".bar2")),
),
Or(
GreaterThan(".foo5", literal.Float(5.2)),
GreaterThanOrEqual(".foo6", literal.Float(6.2)),
),
Not(Like(".foo7", "*@example.com")),
All(".foo8", LessThan(".foo3", literal.Int(3))),
Any(".foo9", LessThanOrEqual(".foo4", literal.Int(4))),
))
}

View File

@@ -9,9 +9,9 @@ import (
const (
// MaxInt53 represents the maximum safe integer in JavaScript (2^53 - 1)
MaxInt53 = 9007199254740991
MaxInt53 int64 = 9007199254740991
// MinInt53 represents the minimum safe integer in JavaScript (-2^53 + 1)
MinInt53 = -9007199254740991
MinInt53 int64 = -9007199254740991
)
func ValidateIntegerBoundsIPLD(node ipld.Node) error {

View File

@@ -185,7 +185,7 @@ func anyAssemble(val any) qp.Assemble {
return qp.Int(i)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
u := rv.Uint()
if u > limits.MaxInt53 {
if u > uint64(limits.MaxInt53) {
panic(fmt.Sprintf("unsigned integer %d exceeds safe bounds", u))
}
return qp.Int(int64(u))

View File

@@ -68,7 +68,7 @@ func Parse(str string) (Selector, error) {
if err != nil {
return nil, newParseError("invalid index", str, col, tok)
}
if idx > limits.MaxInt53 || idx < limits.MinInt53 {
if int64(idx) > limits.MaxInt53 || int64(idx) < limits.MinInt53 {
return nil, newParseError(fmt.Sprintf("index %d exceeds safe integer bounds", idx), str, col, tok)
}
sel = append(sel, segment{str: tok, optional: opt, index: idx})

View File

@@ -16,7 +16,8 @@ import (
"strings"
"time"
"github.com/ucan-wg/go-ucan/did"
"github.com/MetaMask/go-did-it"
"github.com/ucan-wg/go-ucan/pkg/command"
"github.com/ucan-wg/go-ucan/pkg/meta"
"github.com/ucan-wg/go-ucan/pkg/policy"
@@ -83,7 +84,7 @@ func New(iss did.DID, aud did.DID, cmd command.Command, pol policy.Policy, sub d
}
// Root creates a validated UCAN delegation Token from the provided parameters and options.
// This is typically used to create and give a power to an agent.
// This is typically used to create and give power to an agent.
//
// You can read it as "(issuer) allows (audience) to perform (cmd+pol) on itself".
func Root(iss did.DID, aud did.DID, cmd command.Command, pol policy.Policy, opts ...Option) (*Token, error) {
@@ -102,7 +103,7 @@ func Root(iss did.DID, aud did.DID, cmd command.Command, pol policy.Policy, opts
//
// You can read it as "(issuer) allows (audience) to perform (cmd+pol) on anything".
func Powerline(iss did.DID, aud did.DID, cmd command.Command, pol policy.Policy, opts ...Option) (*Token, error) {
return New(iss, aud, cmd, pol, did.Undef, opts...)
return New(iss, aud, cmd, pol, nil, opts...)
}
// Issuer returns the did.DID representing the Token's issuer.
@@ -154,6 +155,16 @@ func (t *Token) Expiration() *time.Time {
return t.expiration
}
// IsRoot tells if the token is a root delegation.
func (t *Token) IsRoot() bool {
return t.issuer.Equal(t.subject)
}
// IsPowerline tells if the token is a powerline delegation.
func (t *Token) IsPowerline() bool {
return t.subject == nil
}
// IsValidNow verifies that the token can be used at the current time, based on expiration or "not before" fields.
// This does NOT do any other kind of verifications.
func (t *Token) IsValidNow() bool {
@@ -179,7 +190,7 @@ func (t *Token) String() string {
switch {
case t.issuer == t.subject:
kind = " (root delegation)"
case t.subject == did.Undef:
case t.subject == nil:
kind = " (powerline delegation)"
default:
kind = " (normal delegation)"
@@ -202,7 +213,7 @@ func (t *Token) validate() error {
var errs error
requiredDID := func(id did.DID, fieldname string) {
if !id.Defined() {
if id == nil {
errs = errors.Join(errs, fmt.Errorf(`a valid did is required for %s: %s`, fieldname, id.String()))
}
}
@@ -227,7 +238,7 @@ func tokenFromModel(m tokenPayloadModel) (*Token, error) {
tkn.issuer, err = did.Parse(m.Iss)
if err != nil {
return nil, fmt.Errorf("parse iss: %w", err)
return nil, fmt.Errorf("parse issuer: %w", err)
}
if tkn.audience, err = did.Parse(m.Aud); err != nil {

View File

@@ -1,57 +1,43 @@
package delegation_test
import (
_ "embed"
"encoding/base64"
"testing"
"time"
"github.com/MetaMask/go-did-it/didtest"
"github.com/stretchr/testify/require"
"gotest.tools/v3/golden"
"github.com/ucan-wg/go-ucan/did/didtest"
"github.com/ucan-wg/go-ucan/pkg/command"
"github.com/ucan-wg/go-ucan/pkg/policy"
"github.com/ucan-wg/go-ucan/token/delegation"
)
//go:embed testdata/new.dagjson
var newDagJson []byte
//go:embed testdata/powerline.dagjson
var powerlineDagJson []byte
//go:embed testdata/root.dagjson
var rootDagJson []byte
const (
nonce = "6roDhGi0kiNriQAz7J3d+bOeoI/tj8ENikmQNbtjnD0"
subJectCmd = "/foo/bar"
subjectPol = `
[
[
"==",
".status",
"draft"
["==", ".status", "draft"],
["all", ".reviewer",
["like", ".email", "*@example.com"]
],
[
"all",
".reviewer",
[
"like",
".email",
"*@example.com"
]
],
[
"any",
".tags",
[
"or",
[
[
"==",
".",
"news"
],
[
"==",
".",
"press"
]
]
]
["any", ".tags",
["or", [
["==", ".", "news"],
["==", ".", "press"]
]]
]
]
`
@@ -80,15 +66,16 @@ func TestConstructors(t *testing.T) {
)
require.NoError(t, err)
require.False(t, tkn.IsRoot())
require.False(t, tkn.IsPowerline())
data, err := tkn.ToDagJson(didtest.PersonaAlice.PrivKey())
require.NoError(t, err)
golden.Assert(t, string(data), "new.dagjson")
require.Equal(t, newDagJson, data)
})
t.Run("Root", func(t *testing.T) {
t.Parallel()
tkn, err := delegation.Root(didtest.PersonaAlice.DID(), didtest.PersonaBob.DID(), cmd, pol,
delegation.WithNonce([]byte(nonce)),
delegation.WithExpiration(exp),
@@ -97,15 +84,16 @@ func TestConstructors(t *testing.T) {
)
require.NoError(t, err)
require.True(t, tkn.IsRoot())
require.False(t, tkn.IsPowerline())
data, err := tkn.ToDagJson(didtest.PersonaAlice.PrivKey())
require.NoError(t, err)
golden.Assert(t, string(data), "root.dagjson")
require.Equal(t, rootDagJson, data)
})
t.Run("Powerline", func(t *testing.T) {
t.Parallel()
tkn, err := delegation.Powerline(didtest.PersonaAlice.DID(), didtest.PersonaBob.DID(), cmd, pol,
delegation.WithNonce([]byte(nonce)),
delegation.WithExpiration(exp),
@@ -114,10 +102,13 @@ func TestConstructors(t *testing.T) {
)
require.NoError(t, err)
require.False(t, tkn.IsRoot())
require.True(t, tkn.IsPowerline())
data, err := tkn.ToDagJson(didtest.PersonaAlice.PrivKey())
require.NoError(t, err)
golden.Assert(t, string(data), "powerline.dagjson")
require.Equal(t, powerlineDagJson, data)
})
}

View File

@@ -9,11 +9,12 @@ import (
"slices"
"time"
"github.com/MetaMask/go-did-it"
didkeyctl "github.com/MetaMask/go-did-it/controller/did-key"
"github.com/MetaMask/go-did-it/crypto"
"github.com/MetaMask/go-did-it/didtest"
"github.com/ipfs/go-cid"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/ucan-wg/go-ucan/did"
"github.com/ucan-wg/go-ucan/did/didtest"
"github.com/ucan-wg/go-ucan/pkg/command"
"github.com/ucan-wg/go-ucan/pkg/policy"
"github.com/ucan-wg/go-ucan/pkg/policy/policytest"
@@ -30,7 +31,7 @@ const (
var constantNonce = []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b}
type newDelegationParams struct {
privKey crypto.PrivKey // iss
privKey crypto.PrivateKeySigningBytes // iss
aud did.DID
cmd command.Command
pol policy.Policy
@@ -70,6 +71,25 @@ type generator struct {
chains []proof
}
func (g *generator) createSelfDelegations(personas []didtest.Persona) error {
for _, persona := range personas {
_, err := g.createDelegation(newDelegationParams{
privKey: persona.PrivKey(),
aud: persona.DID(),
cmd: delegationtest.NominalCommand,
pol: policytest.EmptyPolicy,
sub: persona.DID(),
opts: []delegation.Option{
delegation.WithNonce(constantNonce),
},
}, persona.Name()+persona.Name(), noopVariant())
if err != nil {
return err
}
}
return nil
}
func (g *generator) chainPersonas(personas []didtest.Persona, acc acc, vari variant) error {
acc.name += personas[0].Name()
@@ -157,10 +177,7 @@ func (g *generator) chainPersonas(personas []didtest.Persona, acc acc, vari vari
func (g *generator) createDelegation(params newDelegationParams, name string, vari variant) (cid.Cid, error) {
vari.variant(&params)
issDID, err := did.FromPrivKey(params.privKey)
if err != nil {
return cid.Undef, err
}
issDID := didkeyctl.FromPrivateKey(params.privKey)
tkn, err := delegation.New(issDID, params.aud, params.cmd, params.pol, params.sub, params.opts...)
if err != nil {
@@ -242,7 +259,7 @@ func (g *generator) writeGoFile() error {
Println("}")
Println()
Println("var AllBundles = []*delegation.Bundle{")
Println("var AllBundles = []delegation.Bundle{")
for _, d := range g.dlgs {
Printf("\t%sBundle,\n", d.name)
}

View File

@@ -1,12 +1,16 @@
package main
import (
"github.com/ucan-wg/go-ucan/did/didtest"
"github.com/MetaMask/go-did-it/didtest"
)
func main() {
gen := &generator{}
err := gen.chainPersonas(didtest.Personas(), acc{}, noopVariant())
err := gen.createSelfDelegations(didtest.Personas())
if err != nil {
panic(err)
}
err = gen.chainPersonas(didtest.Personas(), acc{}, noopVariant())
if err != nil {
panic(err)
}

View File

@@ -5,6 +5,7 @@ import (
"path/filepath"
"sync"
_ "github.com/MetaMask/go-did-it/verifiers/did-key"
"github.com/ipfs/go-cid"
"github.com/ucan-wg/go-ucan/pkg/command"
@@ -38,7 +39,7 @@ var fs embed.FS
var _ delegation.Loader = (*DelegationLoader)(nil)
type DelegationLoader struct {
bundles map[cid.Cid]*delegation.Bundle
bundles map[cid.Cid]delegation.Bundle
}
var (
@@ -75,7 +76,7 @@ func loadDelegations() (*DelegationLoader, error) {
return nil, err
}
bundles := make(map[cid.Cid]*delegation.Bundle, len(dirEntries))
bundles := make(map[cid.Cid]delegation.Bundle, len(dirEntries))
for _, dirEntry := range dirEntries {
data, err := fs.ReadFile(filepath.Join(TokenDir, dirEntry.Name()))
@@ -88,7 +89,7 @@ func loadDelegations() (*DelegationLoader, error) {
return nil, err
}
bundles[id] = &delegation.Bundle{Cid: id, Decoded: tkn, Sealed: data}
bundles[id] = delegation.Bundle{Cid: id, Decoded: tkn, Sealed: data}
}
return &DelegationLoader{
@@ -106,7 +107,7 @@ func CidToName(id cid.Cid) string {
return cidToName[id]
}
func mustGetBundle(id cid.Cid) *delegation.Bundle {
func mustGetBundle(id cid.Cid) delegation.Bundle {
bundle, ok := GetDelegationLoader().bundles[id]
if !ok {
panic(delegation.ErrDelegationNotFound)

View File

@@ -9,167 +9,215 @@ import (
)
var (
TokenAliceBobCID = cid.MustParse("bafyreicidrwvmac5lvjypucgityrtjsknojraio7ujjli4r5eyby66wjzm")
TokenAliceAliceCID = cid.MustParse("bafyreiddqsv5rrpcormtcs3dg7hzwjr2grxyyozc2f2surxdbnctdqpfzi")
TokenAliceAliceSealed = mustGetBundle(TokenAliceAliceCID).Sealed
TokenAliceAliceBundle = mustGetBundle(TokenAliceAliceCID)
TokenAliceAlice = mustGetBundle(TokenAliceAliceCID).Decoded
)
var (
TokenBobBobCID = cid.MustParse("bafyreid4dwdov4yijvnb7xxhcndsxifzw5yry4sm4frex6relttlnledo4")
TokenBobBobSealed = mustGetBundle(TokenBobBobCID).Sealed
TokenBobBobBundle = mustGetBundle(TokenBobBobCID)
TokenBobBob = mustGetBundle(TokenBobBobCID).Decoded
)
var (
TokenCarolCarolCID = cid.MustParse("bafyreiekuehdsubdfllqecsat4gsfveyqq6442ejuiqfsgu3tplrus5l3e")
TokenCarolCarolSealed = mustGetBundle(TokenCarolCarolCID).Sealed
TokenCarolCarolBundle = mustGetBundle(TokenCarolCarolCID)
TokenCarolCarol = mustGetBundle(TokenCarolCarolCID).Decoded
)
var (
TokenDanDanCID = cid.MustParse("bafyreigzd442yhyizbx54kd76ewxssh5owuxv26ziittnblnj4h3a555dm")
TokenDanDanSealed = mustGetBundle(TokenDanDanCID).Sealed
TokenDanDanBundle = mustGetBundle(TokenDanDanCID)
TokenDanDan = mustGetBundle(TokenDanDanCID).Decoded
)
var (
TokenErinErinCID = cid.MustParse("bafyreigl5lbogpzq7iyz6qkzhicv4zscu26j62k4ydgcqogdiqmks5tz7q")
TokenErinErinSealed = mustGetBundle(TokenErinErinCID).Sealed
TokenErinErinBundle = mustGetBundle(TokenErinErinCID)
TokenErinErin = mustGetBundle(TokenErinErinCID).Decoded
)
var (
TokenFrankFrankCID = cid.MustParse("bafyreic6hgmqf2vwszboldlqeobpy2plpkcmj4dhhug76akcnafb2pt6em")
TokenFrankFrankSealed = mustGetBundle(TokenFrankFrankCID).Sealed
TokenFrankFrankBundle = mustGetBundle(TokenFrankFrankCID)
TokenFrankFrank = mustGetBundle(TokenFrankFrankCID).Decoded
)
var (
TokenAliceBobCID = cid.MustParse("bafyreifa35rjstdm37cjudzs72ab22rnh5blny725khtapox63fnsj6pbe")
TokenAliceBobSealed = mustGetBundle(TokenAliceBobCID).Sealed
TokenAliceBobBundle = mustGetBundle(TokenAliceBobCID)
TokenAliceBob = mustGetBundle(TokenAliceBobCID).Decoded
)
var (
TokenBobCarolCID = cid.MustParse("bafyreihxv2uhq43oxllzs2xfvxst7wtvvvl7pohb2chcz6hjvfv2ntea5u")
TokenBobCarolCID = cid.MustParse("bafyreiaysaafvfplhjsjywaqfletlr2sziui3sekkczwp2srszdoezwc7u")
TokenBobCarolSealed = mustGetBundle(TokenBobCarolCID).Sealed
TokenBobCarolBundle = mustGetBundle(TokenBobCarolCID)
TokenBobCarol = mustGetBundle(TokenBobCarolCID).Decoded
)
var (
TokenCarolDanCID = cid.MustParse("bafyreihclsgiroazq3heqdswvj2cafwqbpboicq7immo65scl7ahktpsdq")
TokenCarolDanCID = cid.MustParse("bafyreibwpzxcvrere7g5riv3dhza4xibrvulxcvj2nwxu6ozp572o2sbfa")
TokenCarolDanSealed = mustGetBundle(TokenCarolDanCID).Sealed
TokenCarolDanBundle = mustGetBundle(TokenCarolDanCID)
TokenCarolDan = mustGetBundle(TokenCarolDanCID).Decoded
)
var (
TokenDanErinCID = cid.MustParse("bafyreicja6ihewy64p3ake56xukotafjlkh4uqep2qhj52en46zzfwby3e")
TokenDanErinCID = cid.MustParse("bafyreichxodkcokcbvomxhmlf3g3j3zokruxvca63itynf7ib3hsmi4hla")
TokenDanErinSealed = mustGetBundle(TokenDanErinCID).Sealed
TokenDanErinBundle = mustGetBundle(TokenDanErinCID)
TokenDanErin = mustGetBundle(TokenDanErinCID).Decoded
)
var (
TokenErinFrankCID = cid.MustParse("bafyreicjlx3lobxm6hl5s4htd4ydwkkqeiou6rft4rnvulfdyoew565vka")
TokenErinFrankCID = cid.MustParse("bafyreigg434khwxqyfasnk63pi542uwtbrlpfd5sgjfrddqqcba3tardlu")
TokenErinFrankSealed = mustGetBundle(TokenErinFrankCID).Sealed
TokenErinFrankBundle = mustGetBundle(TokenErinFrankCID)
TokenErinFrank = mustGetBundle(TokenErinFrankCID).Decoded
)
var (
TokenCarolDan_InvalidExpandedCommandCID = cid.MustParse("bafyreid3m3pk53gqgp5rlzqhvpedbwsqbidqlp4yz64vknwbzj7bxrmsr4")
TokenCarolDan_InvalidExpandedCommandCID = cid.MustParse("bafyreifxdve23izhlg7fhzqh32i6wxtw33rqidm3cb72pghxlovnensjwe")
TokenCarolDan_InvalidExpandedCommandSealed = mustGetBundle(TokenCarolDan_InvalidExpandedCommandCID).Sealed
TokenCarolDan_InvalidExpandedCommandBundle = mustGetBundle(TokenCarolDan_InvalidExpandedCommandCID)
TokenCarolDan_InvalidExpandedCommand = mustGetBundle(TokenCarolDan_InvalidExpandedCommandCID).Decoded
)
var (
TokenDanErin_InvalidExpandedCommandCID = cid.MustParse("bafyreifn4sy5onwajx3kqvot5mib6m6xarzrqjozqbzgmzpmc5ox3g2uzm")
TokenDanErin_InvalidExpandedCommandCID = cid.MustParse("bafyreieblevkqh2xnbr4x5mosvwv7rboat7ip6ucqvefb2pomrb4qjg4wu")
TokenDanErin_InvalidExpandedCommandSealed = mustGetBundle(TokenDanErin_InvalidExpandedCommandCID).Sealed
TokenDanErin_InvalidExpandedCommandBundle = mustGetBundle(TokenDanErin_InvalidExpandedCommandCID)
TokenDanErin_InvalidExpandedCommand = mustGetBundle(TokenDanErin_InvalidExpandedCommandCID).Decoded
)
var (
TokenErinFrank_InvalidExpandedCommandCID = cid.MustParse("bafyreidmpgd36jznmq42bs34o4qi3fcbrsh4idkg6ejahudejzwb76fwxe")
TokenErinFrank_InvalidExpandedCommandCID = cid.MustParse("bafyreia2ckukamhpeqpcdhevr75ym66vqem432dx4dwbdrdkh63pke3r3i")
TokenErinFrank_InvalidExpandedCommandSealed = mustGetBundle(TokenErinFrank_InvalidExpandedCommandCID).Sealed
TokenErinFrank_InvalidExpandedCommandBundle = mustGetBundle(TokenErinFrank_InvalidExpandedCommandCID)
TokenErinFrank_InvalidExpandedCommand = mustGetBundle(TokenErinFrank_InvalidExpandedCommandCID).Decoded
)
var (
TokenCarolDan_ValidAttenuatedCommandCID = cid.MustParse("bafyreiekhtm237vyapk3c6voeb5lnz54crebqdqi3x4wn4u4cbrrhzsqfe")
TokenCarolDan_ValidAttenuatedCommandCID = cid.MustParse("bafyreibftsq3mhjd5itg6jbos4doccwspvmnilpuduniv2el7mnl45z33y")
TokenCarolDan_ValidAttenuatedCommandSealed = mustGetBundle(TokenCarolDan_ValidAttenuatedCommandCID).Sealed
TokenCarolDan_ValidAttenuatedCommandBundle = mustGetBundle(TokenCarolDan_ValidAttenuatedCommandCID)
TokenCarolDan_ValidAttenuatedCommand = mustGetBundle(TokenCarolDan_ValidAttenuatedCommandCID).Decoded
)
var (
TokenDanErin_ValidAttenuatedCommandCID = cid.MustParse("bafyreicrvzqferyy7rgo75l5rn6r2nl7zyeexxjmu3dm4ff7rn2coblj4y")
TokenDanErin_ValidAttenuatedCommandCID = cid.MustParse("bafyreig5gsifqn3afnyaoqtjhnud2w7tnrda57eiel3d45vbp47hjyayey")
TokenDanErin_ValidAttenuatedCommandSealed = mustGetBundle(TokenDanErin_ValidAttenuatedCommandCID).Sealed
TokenDanErin_ValidAttenuatedCommandBundle = mustGetBundle(TokenDanErin_ValidAttenuatedCommandCID)
TokenDanErin_ValidAttenuatedCommand = mustGetBundle(TokenDanErin_ValidAttenuatedCommandCID).Decoded
)
var (
TokenErinFrank_ValidAttenuatedCommandCID = cid.MustParse("bafyreie6fhspk53kplcc2phla3e7z7fzldlbmmpuwk6nbow5q6s2zjmw2q")
TokenErinFrank_ValidAttenuatedCommandCID = cid.MustParse("bafyreiex2qyrw3xmye4fk5wdf6ukea3ojbokq77k6y566hupj6cicszi3e")
TokenErinFrank_ValidAttenuatedCommandSealed = mustGetBundle(TokenErinFrank_ValidAttenuatedCommandCID).Sealed
TokenErinFrank_ValidAttenuatedCommandBundle = mustGetBundle(TokenErinFrank_ValidAttenuatedCommandCID)
TokenErinFrank_ValidAttenuatedCommand = mustGetBundle(TokenErinFrank_ValidAttenuatedCommandCID).Decoded
)
var (
TokenCarolDan_InvalidSubjectCID = cid.MustParse("bafyreifgksz6756if42tnc6rqsnbaa2u3fdrveo7ek44lnj2d64d5sw26u")
TokenCarolDan_InvalidSubjectCID = cid.MustParse("bafyreie7snyknubaeh4ruig7wxvos54b7skmwsnegf6k23bsffs5btbiiq")
TokenCarolDan_InvalidSubjectSealed = mustGetBundle(TokenCarolDan_InvalidSubjectCID).Sealed
TokenCarolDan_InvalidSubjectBundle = mustGetBundle(TokenCarolDan_InvalidSubjectCID)
TokenCarolDan_InvalidSubject = mustGetBundle(TokenCarolDan_InvalidSubjectCID).Decoded
)
var (
TokenDanErin_InvalidSubjectCID = cid.MustParse("bafyreibdwew5nypsxrm4fq73wu6hw3lgwwiolj3bi33xdrbgcf3ogm6fty")
TokenDanErin_InvalidSubjectCID = cid.MustParse("bafyreicrfmlw4nqqk5t7j6r7ct3c7jlxeasyetb6fq3556vmtihcnbi54i")
TokenDanErin_InvalidSubjectSealed = mustGetBundle(TokenDanErin_InvalidSubjectCID).Sealed
TokenDanErin_InvalidSubjectBundle = mustGetBundle(TokenDanErin_InvalidSubjectCID)
TokenDanErin_InvalidSubject = mustGetBundle(TokenDanErin_InvalidSubjectCID).Decoded
)
var (
TokenErinFrank_InvalidSubjectCID = cid.MustParse("bafyreicr364mj3n7x4iyhcksxypelktcqkkw3ptg7ggxtqegw3p3mr6zc4")
TokenErinFrank_InvalidSubjectCID = cid.MustParse("bafyreietx2sjsm72sbgjnosdnejwlqc5dadlolh2bjl6ifxdllslup7ecm")
TokenErinFrank_InvalidSubjectSealed = mustGetBundle(TokenErinFrank_InvalidSubjectCID).Sealed
TokenErinFrank_InvalidSubjectBundle = mustGetBundle(TokenErinFrank_InvalidSubjectCID)
TokenErinFrank_InvalidSubject = mustGetBundle(TokenErinFrank_InvalidSubjectCID).Decoded
)
var (
TokenCarolDan_InvalidExpiredCID = cid.MustParse("bafyreifyzm5jkx2sfu5awyndg3dn5zlg7sq5hssgfatafk62kiiilapnqe")
TokenCarolDan_InvalidExpiredCID = cid.MustParse("bafyreifhdiem6r5fh3wwaa6uszqe5uashfwaastqjyvzssbiju4mravx3y")
TokenCarolDan_InvalidExpiredSealed = mustGetBundle(TokenCarolDan_InvalidExpiredCID).Sealed
TokenCarolDan_InvalidExpiredBundle = mustGetBundle(TokenCarolDan_InvalidExpiredCID)
TokenCarolDan_InvalidExpired = mustGetBundle(TokenCarolDan_InvalidExpiredCID).Decoded
)
var (
TokenDanErin_InvalidExpiredCID = cid.MustParse("bafyreihhnisabmkofuk3qaw37leijxqjaz5or6v2cufjxwzdkvuvv2dzbq")
TokenDanErin_InvalidExpiredCID = cid.MustParse("bafyreiff7fqutstzz2ep5gzs2mqnt4rka7ezscrzpijyc4jjeopqm7oxxq")
TokenDanErin_InvalidExpiredSealed = mustGetBundle(TokenDanErin_InvalidExpiredCID).Sealed
TokenDanErin_InvalidExpiredBundle = mustGetBundle(TokenDanErin_InvalidExpiredCID)
TokenDanErin_InvalidExpired = mustGetBundle(TokenDanErin_InvalidExpiredCID).Decoded
)
var (
TokenErinFrank_InvalidExpiredCID = cid.MustParse("bafyreigeokaziviwm5kzmkpwesj3gta5k7zrd62x4a746fnrnkhvatwbna")
TokenErinFrank_InvalidExpiredCID = cid.MustParse("bafyreigxfwcynzsy4v4po36s3mz5nf6mg4kpptw6rpld3sc3c3mthq4noa")
TokenErinFrank_InvalidExpiredSealed = mustGetBundle(TokenErinFrank_InvalidExpiredCID).Sealed
TokenErinFrank_InvalidExpiredBundle = mustGetBundle(TokenErinFrank_InvalidExpiredCID)
TokenErinFrank_InvalidExpired = mustGetBundle(TokenErinFrank_InvalidExpiredCID).Decoded
)
var (
TokenCarolDan_InvalidInactiveCID = cid.MustParse("bafyreicea5y2nvlitvxijkupeavtg23i7ktjk3uejnaquguurzptiabk4u")
TokenCarolDan_InvalidInactiveCID = cid.MustParse("bafyreifw4j2mxg4bovuhihvnhqgln7m57lvajt6fza4x4jc7sncyh66wxm")
TokenCarolDan_InvalidInactiveSealed = mustGetBundle(TokenCarolDan_InvalidInactiveCID).Sealed
TokenCarolDan_InvalidInactiveBundle = mustGetBundle(TokenCarolDan_InvalidInactiveCID)
TokenCarolDan_InvalidInactive = mustGetBundle(TokenCarolDan_InvalidInactiveCID).Decoded
)
var (
TokenDanErin_InvalidInactiveCID = cid.MustParse("bafyreifsgqzkmxj2vexuts3z766mwcjreiisjg2jykyzf7tbj5sclutpvq")
TokenDanErin_InvalidInactiveCID = cid.MustParse("bafyreigrrfefw4wvjitiheonigeldnem2loo4yp5cghdskteunuxyozkiq")
TokenDanErin_InvalidInactiveSealed = mustGetBundle(TokenDanErin_InvalidInactiveCID).Sealed
TokenDanErin_InvalidInactiveBundle = mustGetBundle(TokenDanErin_InvalidInactiveCID)
TokenDanErin_InvalidInactive = mustGetBundle(TokenDanErin_InvalidInactiveCID).Decoded
)
var (
TokenErinFrank_InvalidInactiveCID = cid.MustParse("bafyreifbfegon24c6dndiqyktahzs65vhyasrygbw7nhsvojn6distsdre")
TokenErinFrank_InvalidInactiveCID = cid.MustParse("bafyreicdlvnc7iinl2eay3xc3yvtmwezifvfxywjud3defssstusngt6du")
TokenErinFrank_InvalidInactiveSealed = mustGetBundle(TokenErinFrank_InvalidInactiveCID).Sealed
TokenErinFrank_InvalidInactiveBundle = mustGetBundle(TokenErinFrank_InvalidInactiveCID)
TokenErinFrank_InvalidInactive = mustGetBundle(TokenErinFrank_InvalidInactiveCID).Decoded
)
var (
TokenCarolDan_ValidExamplePolicyCID = cid.MustParse("bafyreibtfrp2njnkjrcuhxd4ebaecmpcql5knek2h2j2fjzu2sij2tv6ei")
TokenCarolDan_ValidExamplePolicyCID = cid.MustParse("bafyreidvi5y42befcnb2qud23yt5memf4itn2v6xmw7gvdpihbnanvgqly")
TokenCarolDan_ValidExamplePolicySealed = mustGetBundle(TokenCarolDan_ValidExamplePolicyCID).Sealed
TokenCarolDan_ValidExamplePolicyBundle = mustGetBundle(TokenCarolDan_ValidExamplePolicyCID)
TokenCarolDan_ValidExamplePolicy = mustGetBundle(TokenCarolDan_ValidExamplePolicyCID).Decoded
)
var (
TokenDanErin_ValidExamplePolicyCID = cid.MustParse("bafyreidxfwbkzujpu7ivulkc7b6ff4cpbzrkeklmxqvyhhmkmym5b45e2e")
TokenDanErin_ValidExamplePolicyCID = cid.MustParse("bafyreid3mr53fjsntyyfbbzjx2n32d7atj3v4ztfufdkamrodm6kcjww64")
TokenDanErin_ValidExamplePolicySealed = mustGetBundle(TokenDanErin_ValidExamplePolicyCID).Sealed
TokenDanErin_ValidExamplePolicyBundle = mustGetBundle(TokenDanErin_ValidExamplePolicyCID)
TokenDanErin_ValidExamplePolicy = mustGetBundle(TokenDanErin_ValidExamplePolicyCID).Decoded
)
var (
TokenErinFrank_ValidExamplePolicyCID = cid.MustParse("bafyreiatkvtvgakqcrdk6vgrv7tbq5rbeiqct52ep4plcftp2agffjyvp4")
TokenErinFrank_ValidExamplePolicyCID = cid.MustParse("bafyreiegytubdwqnl3gd7dddfmqhr4kyo4sb5446kjyqvvolk2wmwum6ae")
TokenErinFrank_ValidExamplePolicySealed = mustGetBundle(TokenErinFrank_ValidExamplePolicyCID).Sealed
TokenErinFrank_ValidExamplePolicyBundle = mustGetBundle(TokenErinFrank_ValidExamplePolicyCID)
TokenErinFrank_ValidExamplePolicy = mustGetBundle(TokenErinFrank_ValidExamplePolicyCID).Decoded
)
var AllTokens = []*delegation.Token{
TokenAliceAlice,
TokenBobBob,
TokenCarolCarol,
TokenDanDan,
TokenErinErin,
TokenFrankFrank,
TokenAliceBob,
TokenBobCarol,
TokenCarolDan,
@@ -195,7 +243,13 @@ var AllTokens = []*delegation.Token{
TokenErinFrank_ValidExamplePolicy,
}
var AllBundles = []*delegation.Bundle{
var AllBundles = []delegation.Bundle{
TokenAliceAliceBundle,
TokenBobBobBundle,
TokenCarolCarolBundle,
TokenDanDanBundle,
TokenErinErinBundle,
TokenFrankFrankBundle,
TokenAliceBobBundle,
TokenBobCarolBundle,
TokenCarolDanBundle,
@@ -222,6 +276,12 @@ var AllBundles = []*delegation.Bundle{
}
var cidToName = map[cid.Cid]string{
TokenAliceAliceCID: "TokenAliceAlice",
TokenBobBobCID: "TokenBobBob",
TokenCarolCarolCID: "TokenCarolCarol",
TokenDanDanCID: "TokenDanDan",
TokenErinErinCID: "TokenErinErin",
TokenFrankFrankCID: "TokenFrankFrank",
TokenAliceBobCID: "TokenAliceBob",
TokenBobCarolCID: "TokenBobCarol",
TokenCarolDanCID: "TokenCarolDan",

View File

@@ -8,12 +8,12 @@ import (
"fmt"
"time"
"github.com/MetaMask/go-did-it/didtest"
"github.com/ipfs/go-cid"
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/codec/dagcbor"
"github.com/ipld/go-ipld-prime/codec/dagjson"
"github.com/ucan-wg/go-ucan/did/didtest"
"github.com/ucan-wg/go-ucan/pkg/command"
"github.com/ucan-wg/go-ucan/pkg/policy"
"github.com/ucan-wg/go-ucan/pkg/policy/literal"
@@ -57,37 +57,37 @@ func ExampleNew() {
// Example output:
//
// issDid: did:key:z6MkvJPmEZZYbgiw1ouT1oouTsTFBHJSts9ophVsNgcRmYxU
// issDid: did:key:z6Mkf4WtCwPDtamsZvBJA4eSVcE7vZuRPy5Skm4HaoQv81i1
//
// CID (base58BTC): zdpuAsqfZkgg2jgZyob23sq1J9xwtf9PHgt1PsskVCMq7Vvxk
// CID (base58BTC): zdpuB1bzMdGAtzBej9ZBJbW3ppsjP2Cf9KZ8xMjdhUjaf3vz1
//
// DAG-CBOR (base64) out: lhAOnjc0bPptlI5MxRBrIK3YmAP1CxKfXOPkz6MHt/UJCx2gCN+6gXZX2N+BIJvmy8XmAO5sT2GYimiV7HlJH1AA6JhaEQ07QFxc3VjYW4vZGxnQDEuMC4wLXJjLjGpY2F1ZHg4ZGlkOmtleTp6Nk1rZ3VwY2hoNUh3dUhhaFM3WXN5RThiTHVhMU1yOHAyaUtOUmh5dlN2UkFzOW5jY21kaC9mb28vYmFyY2V4cBpnROP/Y2lzc3g4ZGlkOmtleTp6Nk1rdkpQbUVaWlliZ2l3MW91VDFvb3VUc1RGQkhKU3RzOW9waFZzTmdjUm1ZeFVjbmJmGmdE1itjcG9sg4NiPT1nLnN0YXR1c2VkcmFmdINjYWxsaS5yZXZpZXdlcoNkbGlrZWYuZW1haWxtKkBleGFtcGxlLmNvbYNjYW55ZS50YWdzgmJvcoKDYj09YS5kbmV3c4NiPT1hLmVwcmVzc2NzdWJ4OGRpZDprZXk6ejZNa3V1a2syc2tEWExRbjdOSzNFaDlqTW5kWWZ2REJ4eGt0Z3BpZEpBcWI3TTNwZG1ldGGiY2Jhehh7Y2Zvb2NiYXJlbm9uY2VMv+Diy6GExIuM1eX4
// DAG-CBOR (base64) out: glhAQhZTTb4U1rin/oLFre618Ol5/leaP758T6EkHYfQaNmFYad7yVTer8bbM1Zp2LxrV3eEYeWkHeL3F0V3zWC/CaJhaEg0Ae0B7QETcXN1Y2FuL2RsZ0AxLjAuMC1yYy4xqWNhdWR4OGRpZDprZXk6ejZNa2pXRlU4SHRmTXF1V241TUVROXIyMnpXcXlDTjF2YXpHdzZnNnB6Y2l6aU5WY2NtZGgvZm9vL2JhcmNleHAaaItoW2Npc3N4OGRpZDprZXk6ejZNa2Y0V3RDd1BEdGFtc1p2QkpBNGVTVmNFN3ZadVJQeTVTa200SGFvUXY4MWkxY25iZhpoi1qHY3BvbIODYj09Zy5zdGF0dXNlZHJhZnSDY2FsbGkucmV2aWV3ZXKDZGxpa2VmLmVtYWlsbSpAZXhhbXBsZS5jb22DY2FueWUudGFnc4Jib3KCg2I9PWEuZG5ld3ODYj09YS5lcHJlc3Njc3VieDhkaWQ6a2V5Ono2TWtuVXoxbVNqNHB2UzZhVVVIZWtDSGRVUHY3SEJoRHlEQlpRMlczVnVqYzVxQ2RtZXRhomNiYXoYe2Nmb29jYmFyZW5vbmNlTHa1D4DJ78LvscA/hg==
// Converted to DAG-JSON out:
// [
// {
// "/": {
// "bytes": "5rvl8uKmDVGvAVSt4m/0MGiXl9dZwljJJ9m2qHCoIB617l26UvMxyH5uvN9hM7ozfVATiq4mLhoGgm9IGnEEAg"
// "bytes": "QhZTTb4U1rin/oLFre618Ol5/leaP758T6EkHYfQaNmFYad7yVTer8bbM1Zp2LxrV3eEYeWkHeL3F0V3zWC/CQ"
// }
// },
// {
// "h": {
// "/": {
// "bytes": "NO0BcQ"
// "bytes": "NAHtAe0BE3E"
// }
// },
// "ucan/dlg@1.0.0-rc.1": {
// "aud": "did:key:z6Mkq5YmbJcTrPExNDi26imrTCpKhepjBFBSHqrBDN2ArPkv",
// "aud": "did:key:z6MkjWFU8HtfMquWn5MEQ9r22zWqyCN1vazGw6g6pzciziNV",
// "cmd": "/foo/bar",
// "exp": 1728933098,
// "iss": "did:key:z6MkhVFznPeR572rTK51UjoTNpnF8cxuWfPm9oBMPr7y8ABe",
// "exp": 1753966683,
// "iss": "did:key:z6Mkf4WtCwPDtamsZvBJA4eSVcE7vZuRPy5Skm4HaoQv81i1",
// "meta": {
// "baz": 123,
// "foo": "bar"
// },
// "nbf": 1728929558,
// "nbf": 1753963143,
// "nonce": {
// "/": {
// "bytes": "u0HMgJ5Y+M84I/66"
// "bytes": "drUPgMnvwu+xwD+G"
// }
// },
// "pol": [
@@ -125,7 +125,7 @@ func ExampleNew() {
// ]
// ]
// ],
// "sub": "did:key:z6MktA1uBdCpq4uJBqE9jjMiLyxZBg9a6xgPPKJjMqss6Zc2"
// "sub": "did:key:z6MknUz1mSj4pvS6aUUHekCHdUPv7HBhDyDBZQ2W3Vujc5qC"
// }
// }
// ]
@@ -166,38 +166,36 @@ func ExampleRoot() {
// Example output:
//
// issDid: did:key:z6MknWJqz17Y4AfsXSJUFKomuBR4GTkViM7kJYutzTMkCyFF
//
// CID (base58BTC): zdpuAkwYz8nY7uU8j3F6wVTfFY1VEoExwvUAYBEwRWfTozddE
//
// DAG-CBOR (base64) out: glhAVpW67FJ+myNi+azvnw2jivuiqXTuMrDZI2Qdaa8jE1Oi3mkjnm7DyqSQGADcomcuDslMWKmJ+OIyvbPG5PtSA6JhaEQ07QFxc3VjYW4vZGxnQDEuMC4wLXJjLjGpY2F1ZHg4ZGlkOmtleTp6Nk1rdkpQbUVaWlliZ2l3MW91VDFvb3VUc1RGQkhKU3RzOW9waFZzTmdjUm1ZeFVjY21kaC9mb28vYmFyY2V4cBpnROVoY2lzc3g4ZGlkOmtleTp6Nk1rdXVrazJza0RYTFFuN05LM0VoOWpNbmRZZnZEQnh4a3RncGlkSkFxYjdNM3BjbmJmGmdE15RjcG9sg4NiPT1nLnN0YXR1c2VkcmFmdINjYWxsaS5yZXZpZXdlcoNkbGlrZWYuZW1haWxtKkBleGFtcGxlLmNvbYNjYW55ZS50YWdzgmJvcoKDYj09YS5kbmV3c4NiPT1hLmVwcmVzc2NzdWJ4OGRpZDprZXk6ejZNa3V1a2syc2tEWExRbjdOSzNFaDlqTW5kWWZ2REJ4eGt0Z3BpZEpBcWI3TTNwZG1ldGGiY2Jhehh7Y2Zvb2NiYXJlbm9uY2VMwzDc03WBciJIGPWG
// DAG-CBOR (base64) out: glhATIXb2wnBByq/llaQ4RLoWTxheAwamCNo2sKL8SQJbq0EVRvdfUQDKNpuMVkvtyUR6tUdZlKv1BcXjfGEaF2XAKJhaEg0Ae0B7QETcXN1Y2FuL2RsZ0AxLjAuMC1yYy4xqWNhdWR4OGRpZDprZXk6ejZNa2Y0V3RDd1BEdGFtc1p2QkpBNGVTVmNFN3ZadVJQeTVTa200SGFvUXY4MWkxY2NtZGgvZm9vL2JhcmNleHAaaItnfWNpc3N4OGRpZDprZXk6ejZNa25VejFtU2o0cHZTNmFVVUhla0NIZFVQdjdIQmhEeURCWlEyVzNWdWpjNXFDY25iZhpoi1mpY3BvbIODYj09Zy5zdGF0dXNlZHJhZnSDY2FsbGkucmV2aWV3ZXKDZGxpa2VmLmVtYWlsbSpAZXhhbXBsZS5jb22DY2FueWUudGFnc4Jib3KCg2I9PWEuZG5ld3ODYj09YS5lcHJlc3Njc3VieDhkaWQ6a2V5Ono2TWtuVXoxbVNqNHB2UzZhVVVIZWtDSGRVUHY3SEJoRHlEQlpRMlczVnVqYzVxQ2RtZXRhomNiYXoYe2Nmb29jYmFyZW5vbmNlTGxwbjHKcevt5dZ0Xg==
//
// Converted to DAG-JSON out:
// [
// {
// "/": {
// "bytes": "VpW67FJ+myNi+azvnw2jivuiqXTuMrDZI2Qdaa8jE1Oi3mkjnm7DyqSQGADcomcuDslMWKmJ+OIyvbPG5PtSAw"
// "bytes": "TIXb2wnBByq/llaQ4RLoWTxheAwamCNo2sKL8SQJbq0EVRvdfUQDKNpuMVkvtyUR6tUdZlKv1BcXjfGEaF2XAA"
// }
// },
// {
// "h": {
// "/": {
// "bytes": "NO0BcQ"
// "bytes": "NAHtAe0BE3E"
// }
// },
// "ucan/dlg@1.0.0-rc.1": {
// "aud": "did:key:z6MkvJPmEZZYbgiw1ouT1oouTsTFBHJSts9ophVsNgcRmYxU",
// "aud": "did:key:z6Mkf4WtCwPDtamsZvBJA4eSVcE7vZuRPy5Skm4HaoQv81i1",
// "cmd": "/foo/bar",
// "exp": 1732568424,
// "iss": "did:key:z6Mkuukk2skDXLQn7NK3Eh9jMndYfvDBxxktgpidJAqb7M3p",
// "exp": 1753966461,
// "iss": "did:key:z6MknUz1mSj4pvS6aUUHekCHdUPv7HBhDyDBZQ2W3Vujc5qC",
// "meta": {
// "baz": 123,
// "foo": "bar"
// },
// "nbf": 1732564884,
// "nbf": 1753962921,
// "nonce": {
// "/": {
// "bytes": "wzDc03WBciJIGPWG"
// "bytes": "bHBuMcpx6+3l1nRe"
// }
// },
// "pol": [
@@ -235,7 +233,7 @@ func ExampleRoot() {
// ]
// ]
// ],
// "sub": "did:key:z6Mkuukk2skDXLQn7NK3Eh9jMndYfvDBxxktgpidJAqb7M3p"
// "sub": "did:key:z6MknUz1mSj4pvS6aUUHekCHdUPv7HBhDyDBZQ2W3Vujc5qC"
// }
// }
// ]
@@ -244,7 +242,7 @@ func ExampleRoot() {
// The following example demonstrates how to get a delegation.Token from
// a DAG-CBOR []byte.
func ExampleFromSealed() {
const cborBase64 = "glhAmnAkgfjAx4SA5pzJmtaHRJtTGNpF1y6oqb4yhGoM2H2EUGbBYT4rVDjMKBgCjhdGHjipm00L8iR5SsQh3sIEBaJhaEQ07QFxc3VjYW4vZGxnQDEuMC4wLXJjLjGoY2F1ZHg4ZGlkOmtleTp6Nk1rcTVZbWJKY1RyUEV4TkRpMjZpbXJUQ3BLaGVwakJGQlNIcXJCRE4yQXJQa3ZjY21kaC9mb28vYmFyY2V4cPZjaXNzeDhkaWQ6a2V5Ono2TWtwem4ybjNaR1QyVmFxTUdTUUMzdHptelY0VFM5UzcxaUZzRFhFMVdub05IMmNwb2yDg2I9PWcuc3RhdHVzZWRyYWZ0g2NhbGxpLnJldmlld2Vyg2RsaWtlZi5lbWFpbG0qQGV4YW1wbGUuY29tg2NhbnllLnRhZ3OCYm9ygoNiPT1hLmRuZXdzg2I9PWEuZXByZXNzY3N1Yng4ZGlkOmtleTp6Nk1rdEExdUJkQ3BxNHVKQnFFOWpqTWlMeXhaQmc5YTZ4Z1BQS0pqTXFzczZaYzJkbWV0YaBlbm9uY2VMAAECAwQFBgcICQoL"
const cborBase64 = "glhACBuW/rjVKyBPUVPxexsafwBe7y84k0yzywq3hQW2rs2TNmWA5wexAQ+jTkSQ07zhmQRA/wytBfqWkx24+sjlD6JhaEg0Ae0B7QETcXN1Y2FuL2RsZ0AxLjAuMC1yYy4xp2NhdWR4OGRpZDprZXk6ejZNa2pXRlU4SHRmTXF1V241TUVROXIyMnpXcXlDTjF2YXpHdzZnNnB6Y2l6aU5WY2NtZGgvZm9vL2JhcmNleHD2Y2lzc3g4ZGlkOmtleTp6Nk1rZjRXdEN3UER0YW1zWnZCSkE0ZVNWY0U3dlp1UlB5NVNrbTRIYW9RdjgxaTFjcG9sg4NiPT1nLnN0YXR1c2VkcmFmdINjYWxsaS5yZXZpZXdlcoNkbGlrZWYuZW1haWxtKkBleGFtcGxlLmNvbYNjYW55ZS50YWdzgmJvcoKDYj09YS5kbmV3c4NiPT1hLmVwcmVzc2NzdWJ4OGRpZDprZXk6ejZNa25VejFtU2o0cHZTNmFVVUhla0NIZFVQdjdIQmhEeURCWlEyVzNWdWpjNXFDZW5vbmNlTDVJDkO3LVTKnhxKKw=="
cborBytes, err := base64.StdEncoding.DecodeString(cborBase64)
printThenPanicOnErr(err)
@@ -264,10 +262,10 @@ func ExampleFromSealed() {
fmt.Println("Expiration (exp):", tkn.Expiration())
// Output:
// CID (base58BTC): zdpuAw26pFuvZa2Z9YAtpZZnWN6VmnRFr7Z8LVY5c7RVWoxGY
// Issuer (iss): did:key:z6Mkpzn2n3ZGT2VaqMGSQC3tzmzV4TS9S71iFsDXE1WnoNH2
// Audience (aud): did:key:z6Mkq5YmbJcTrPExNDi26imrTCpKhepjBFBSHqrBDN2ArPkv
// Subject (sub): did:key:z6MktA1uBdCpq4uJBqE9jjMiLyxZBg9a6xgPPKJjMqss6Zc2
// CID (base58BTC): zdpuAsgmtmC849BEApGCJm2fTSzwtHiAqQnuJCMBBBCbFiadd
// Issuer (iss): did:key:z6Mkf4WtCwPDtamsZvBJA4eSVcE7vZuRPy5Skm4HaoQv81i1
// Audience (aud): did:key:z6MkjWFU8HtfMquWn5MEQ9r22zWqyCN1vazGw6g6pzciziNV
// Subject (sub): did:key:z6MknUz1mSj4pvS6aUUHekCHdUPv7HBhDyDBZQ2W3Vujc5qC
// Command (cmd): /foo/bar
// Policy (pol): [
// ["==", ".status", "draft"],
@@ -281,7 +279,7 @@ func ExampleFromSealed() {
// ]]
// ]
// ]
// Nonce (nonce): 000102030405060708090a0b
// Nonce (nonce): 35490e43b72d54ca9e1c4a2b
// Meta (meta): {}
// NotBefore (nbf): <nil>
// Expiration (exp): <nil>

View File

@@ -0,0 +1,108 @@
package delegation
import (
_ "embed"
"encoding/base64"
"encoding/json"
"fmt"
"testing"
"github.com/MetaMask/go-did-it/crypto"
"github.com/MetaMask/go-did-it/crypto/ed25519"
"github.com/multiformats/go-varint"
"github.com/stretchr/testify/require"
)
// This comes from https://github.com/ucan-wg/spec/blob/main/fixtures/1.0.0/delegation.json
//
//go:embed testdata/interop_delegation.json
var interopDelegation []byte
type interop struct {
Version string `json:"version"`
Comments string `json:"comments"`
Principals map[string]string `json:"principals"`
Valid []validTestCase `json:"valid"`
}
type validTestCase struct {
Name string `json:"name"`
Token string `json:"token"`
CID string `json:"cid"`
Envelope envelopeData `json:"envelope"`
}
type envelopeData struct {
Payload payloadData `json:"payload"`
Signature string `json:"signature"`
Algorithm string `json:"alg"`
Encoding string `json:"enc"`
Spec string `json:"spec"`
Version string `json:"version"`
}
type payloadData struct {
Issuer string `json:"iss"`
Audience string `json:"aud"`
Subject string `json:"sub"`
Command string `json:"cmd"`
Policies json.RawMessage `json:"pol"`
ExpiresAt int64 `json:"exp"`
Nonce string `json:"nonce"`
}
func TestInterop(t *testing.T) {
var testData interop
err := json.Unmarshal(interopDelegation, &testData)
require.NoError(t, err)
require.Equal(t, "1.0.0-rc.1", testData.Version)
// alice, err := decodeKey(testData.Principals["alice"])
// require.NoError(t, err)
// bob, err := decodeKey(testData.Principals["bob"])
// require.NoError(t, err)
// carol, err := decodeKey(testData.Principals["carol"])
// require.NoError(t, err)
t.Run("valid", func(t *testing.T) {
for _, tc := range testData.Valid {
t.Run(tc.Name, func(t *testing.T) {
dlgBytes, err := base64.StdEncoding.DecodeString(tc.Token)
require.NoError(t, err)
dlg, c, err := FromSealed(dlgBytes)
require.NoError(t, err)
require.Equal(t, tc.CID, c.String())
require.Equal(t, tc.Envelope.Payload.Issuer, dlg.Issuer().String())
require.Equal(t, tc.Envelope.Payload.Audience, dlg.Audience().String())
require.Equal(t, tc.Envelope.Payload.Subject, dlg.Subject().String())
require.Equal(t, tc.Envelope.Payload.Command, dlg.Command().String())
require.Equal(t, tc.Envelope.Payload.Command, dlg.Command().String())
require.JSONEq(t, string(tc.Envelope.Payload.Policies), dlg.Policy().String())
require.Equal(t, tc.Envelope.Payload.ExpiresAt, dlg.expiration.Unix())
nonceBytes, err := base64.StdEncoding.DecodeString(tc.Envelope.Payload.Nonce)
require.NoError(t, err)
require.Equal(t, nonceBytes, dlg.Nonce())
})
}
})
}
func decodeKey(key string) (crypto.PrivateKeySigningBytes, error) {
bytes, err := base64.StdEncoding.DecodeString(key)
if err != nil {
return nil, err
}
code, read, err := varint.FromUvarint(bytes)
if err != nil {
return nil, err
}
if code != 0x1300 {
return nil, fmt.Errorf("invalid varint code: %d", code)
}
return ed25519.PrivateKeyFromSeed(bytes[read:])
}

View File

@@ -1,25 +1,24 @@
package delegation
import (
"fmt"
"io"
"github.com/MetaMask/go-did-it"
"github.com/MetaMask/go-did-it/crypto"
"github.com/ipfs/go-cid"
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/codec"
"github.com/ipld/go-ipld-prime/codec/dagcbor"
"github.com/ipld/go-ipld-prime/codec/dagjson"
"github.com/ipld/go-ipld-prime/datamodel"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/ucan-wg/go-ucan/did"
"github.com/ucan-wg/go-ucan/token/internal/envelope"
)
// ToSealed wraps the delegation token in an envelope, generates the
// signature, encodes the result to DAG-CBOR and calculates the CID of
// the resulting binary data.
func (t *Token) ToSealed(privKey crypto.PrivKey) ([]byte, cid.Cid, error) {
func (t *Token) ToSealed(privKey crypto.PrivateKeySigningBytes) ([]byte, cid.Cid, error) {
data, err := t.ToDagCbor(privKey)
if err != nil {
return nil, cid.Undef, err
@@ -34,7 +33,7 @@ func (t *Token) ToSealed(privKey crypto.PrivKey) ([]byte, cid.Cid, error) {
}
// ToSealedWriter is the same as ToSealed but accepts an io.Writer.
func (t *Token) ToSealedWriter(w io.Writer, privKey crypto.PrivKey) (cid.Cid, error) {
func (t *Token) ToSealedWriter(w io.Writer, privKey crypto.PrivateKeySigningBytes) (cid.Cid, error) {
cidWriter := envelope.NewCIDWriter(w)
if err := t.ToDagCborWriter(cidWriter, privKey); err != nil {
@@ -48,8 +47,8 @@ func (t *Token) ToSealedWriter(w io.Writer, privKey crypto.PrivKey) (cid.Cid, er
// verifies that the envelope's signature is correct based on the public
// key taken from the issuer (iss) field and calculates the CID of the
// incoming data.
func FromSealed(data []byte) (*Token, cid.Cid, error) {
tkn, err := FromDagCbor(data)
func FromSealed(data []byte, resolvOpts ...did.ResolutionOption) (*Token, cid.Cid, error) {
tkn, err := FromDagCbor(data, resolvOpts...)
if err != nil {
return nil, cid.Undef, err
}
@@ -63,10 +62,10 @@ func FromSealed(data []byte) (*Token, cid.Cid, error) {
}
// FromSealedReader is the same as Unseal but accepts an io.Reader.
func FromSealedReader(r io.Reader) (*Token, cid.Cid, error) {
func FromSealedReader(r io.Reader, resolvOpts ...did.ResolutionOption) (*Token, cid.Cid, error) {
cidReader := envelope.NewCIDReader(r)
tkn, err := FromDagCborReader(cidReader)
tkn, err := FromDagCborReader(cidReader, resolvOpts...)
if err != nil {
return nil, cid.Undef, err
}
@@ -81,7 +80,7 @@ func FromSealedReader(r io.Reader) (*Token, cid.Cid, error) {
// Encode marshals a Token to the format specified by the provided
// codec.Encoder.
func (t *Token) Encode(privKey crypto.PrivKey, encFn codec.Encoder) ([]byte, error) {
func (t *Token) Encode(privKey crypto.PrivateKeySigningBytes, encFn codec.Encoder) ([]byte, error) {
node, err := t.toIPLD(privKey)
if err != nil {
return nil, err
@@ -91,7 +90,7 @@ func (t *Token) Encode(privKey crypto.PrivKey, encFn codec.Encoder) ([]byte, err
}
// EncodeWriter is the same as Encode, but accepts an io.Writer.
func (t *Token) EncodeWriter(w io.Writer, privKey crypto.PrivKey, encFn codec.Encoder) error {
func (t *Token) EncodeWriter(w io.Writer, privKey crypto.PrivateKeySigningBytes, encFn codec.Encoder) error {
node, err := t.toIPLD(privKey)
if err != nil {
return err
@@ -101,22 +100,22 @@ func (t *Token) EncodeWriter(w io.Writer, privKey crypto.PrivKey, encFn codec.En
}
// ToDagCbor marshals the Token to the DAG-CBOR format.
func (t *Token) ToDagCbor(privKey crypto.PrivKey) ([]byte, error) {
func (t *Token) ToDagCbor(privKey crypto.PrivateKeySigningBytes) ([]byte, error) {
return t.Encode(privKey, dagcbor.Encode)
}
// ToDagCborWriter is the same as ToDagCbor, but it accepts an io.Writer.
func (t *Token) ToDagCborWriter(w io.Writer, privKey crypto.PrivKey) error {
func (t *Token) ToDagCborWriter(w io.Writer, privKey crypto.PrivateKeySigningBytes) error {
return t.EncodeWriter(w, privKey, dagcbor.Encode)
}
// ToDagJson marshals the Token to the DAG-JSON format.
func (t *Token) ToDagJson(privKey crypto.PrivKey) ([]byte, error) {
func (t *Token) ToDagJson(privKey crypto.PrivateKeySigningBytes) ([]byte, error) {
return t.Encode(privKey, dagjson.Encode)
}
// ToDagJsonWriter is the same as ToDagJson, but it accepts an io.Writer.
func (t *Token) ToDagJsonWriter(w io.Writer, privKey crypto.PrivKey) error {
func (t *Token) ToDagJsonWriter(w io.Writer, privKey crypto.PrivateKeySigningBytes) error {
return t.EncodeWriter(w, privKey, dagjson.Encode)
}
@@ -125,29 +124,29 @@ func (t *Token) ToDagJsonWriter(w io.Writer, privKey crypto.PrivKey) error {
//
// An error is returned if the conversion fails, or if the resulting
// Token is invalid.
func Decode(b []byte, decFn codec.Decoder) (*Token, error) {
func Decode(b []byte, decFn codec.Decoder, resolvOpts ...did.ResolutionOption) (*Token, error) {
node, err := ipld.Decode(b, decFn)
if err != nil {
return nil, err
}
return FromIPLD(node)
return FromIPLD(node, resolvOpts...)
}
// DecodeReader is the same as Decode, but accept an io.Reader.
func DecodeReader(r io.Reader, decFn codec.Decoder) (*Token, error) {
func DecodeReader(r io.Reader, decFn codec.Decoder, resolvOpts ...did.ResolutionOption) (*Token, error) {
node, err := ipld.DecodeStreaming(r, decFn)
if err != nil {
return nil, err
}
return FromIPLD(node)
return FromIPLD(node, resolvOpts...)
}
// FromDagCbor unmarshals the input data into a Token.
//
// An error is returned if the conversion fails, or if the resulting
// Token is invalid.
func FromDagCbor(data []byte) (*Token, error) {
pay, err := envelope.FromDagCbor[*tokenPayloadModel](data)
func FromDagCbor(data []byte, resolvOpts ...did.ResolutionOption) (*Token, error) {
pay, err := envelope.FromDagCbor[*tokenPayloadModel](data, resolvOpts...)
if err != nil {
return nil, err
}
@@ -161,26 +160,26 @@ func FromDagCbor(data []byte) (*Token, error) {
}
// FromDagCborReader is the same as FromDagCbor, but accept an io.Reader.
func FromDagCborReader(r io.Reader) (*Token, error) {
return DecodeReader(r, dagcbor.Decode)
func FromDagCborReader(r io.Reader, resolvOpts ...did.ResolutionOption) (*Token, error) {
return DecodeReader(r, dagcbor.Decode, resolvOpts...)
}
// FromDagJson unmarshals the input data into a Token.
//
// An error is returned if the conversion fails, or if the resulting
// Token is invalid.
func FromDagJson(data []byte) (*Token, error) {
return Decode(data, dagjson.Decode)
func FromDagJson(data []byte, resolvOpts ...did.ResolutionOption) (*Token, error) {
return Decode(data, dagjson.Decode, resolvOpts...)
}
// FromDagJsonReader is the same as FromDagJson, but accept an io.Reader.
func FromDagJsonReader(r io.Reader) (*Token, error) {
return DecodeReader(r, dagjson.Decode)
func FromDagJsonReader(r io.Reader, resolvOpts ...did.ResolutionOption) (*Token, error) {
return DecodeReader(r, dagjson.Decode, resolvOpts...)
}
// FromIPLD decode the given IPLD representation into a Token.
func FromIPLD(node datamodel.Node) (*Token, error) {
pay, err := envelope.FromIPLD[*tokenPayloadModel](node)
func FromIPLD(node datamodel.Node, resolvOpts ...did.ResolutionOption) (*Token, error) {
pay, err := envelope.FromIPLD[*tokenPayloadModel](node, resolvOpts...)
if err != nil {
return nil, err
}
@@ -193,18 +192,9 @@ func FromIPLD(node datamodel.Node) (*Token, error) {
return tkn, err
}
func (t *Token) toIPLD(privKey crypto.PrivKey) (datamodel.Node, error) {
// sanity check that privKey and issuer are matching
issPub, err := t.issuer.PubKey()
if err != nil {
return nil, err
}
if !issPub.Equals(privKey.GetPublic()) {
return nil, fmt.Errorf("private key doesn't match the issuer")
}
func (t *Token) toIPLD(privKey crypto.PrivateKeySigningBytes) (datamodel.Node, error) {
var sub *string
if t.subject != did.Undef {
if t.subject != nil {
s := t.subject.String()
sub = &s
}

View File

@@ -14,10 +14,10 @@ import (
"github.com/ucan-wg/go-ucan/token/internal/envelope"
)
// [Tag] is the string used as a key within the SigPayload that identifies
// Tag is the string used as a key within the SigPayload that identifies
// that the TokenPayload is a delegation.
//
// [Tag]: https://github.com/ucan-wg/delegation/tree/v1_ipld#type-tag
// See: https://github.com/ucan-wg/delegation/tree/v1_ipld#type-tag
const Tag = "ucan/dlg@1.0.0-rc.1"
// TODO: update the above Tag URL once the delegation specification is merged.

View File

@@ -5,12 +5,11 @@ import (
_ "embed"
"testing"
"github.com/MetaMask/go-did-it/didtest"
"github.com/ipld/go-ipld-prime"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gotest.tools/v3/golden"
"github.com/ucan-wg/go-ucan/did/didtest"
"github.com/ucan-wg/go-ucan/token/delegation"
"github.com/ucan-wg/go-ucan/token/internal/envelope"
)
@@ -21,7 +20,6 @@ var schemaBytes []byte
func TestSchemaRoundTrip(t *testing.T) {
t.Parallel()
delegationJson := golden.Get(t, "new.dagjson")
privKey := didtest.PersonaAlice.PrivKey()
t.Run("via buffers", func(t *testing.T) {
@@ -30,7 +28,7 @@ func TestSchemaRoundTrip(t *testing.T) {
// format: dagJson --> PayloadModel --> dagCbor --> PayloadModel --> dagJson
// function: DecodeDagJson() Seal() Unseal() EncodeDagJson()
p1, err := delegation.FromDagJson(delegationJson)
p1, err := delegation.FromDagJson(newDagJson)
require.NoError(t, err)
_, newCID, err := p1.ToSealed(privKey)
@@ -47,13 +45,13 @@ func TestSchemaRoundTrip(t *testing.T) {
readJson, err := p2.ToDagJson(privKey)
require.NoError(t, err)
assert.JSONEq(t, string(delegationJson), string(readJson))
assert.JSONEq(t, string(newDagJson), string(readJson))
})
t.Run("via streaming", func(t *testing.T) {
t.Parallel()
buf := bytes.NewBuffer(delegationJson)
buf := bytes.NewBuffer(newDagJson)
// format: dagJson --> PayloadModel --> dagCbor --> PayloadModel --> dagJson
// function: DecodeDagJson() Seal() Unseal() EncodeDagJson()
@@ -77,17 +75,7 @@ func TestSchemaRoundTrip(t *testing.T) {
readJson := &bytes.Buffer{}
require.NoError(t, p2.ToDagJsonWriter(readJson, privKey))
assert.JSONEq(t, string(delegationJson), readJson.String())
})
t.Run("fails with wrong PrivKey", func(t *testing.T) {
t.Parallel()
p1, err := delegation.FromDagJson(delegationJson)
require.NoError(t, err)
_, _, err = p1.ToSealed(didtest.PersonaBob.PrivKey())
require.EqualError(t, err, "private key doesn't match the issuer")
assert.JSONEq(t, string(newDagJson), readJson.String())
})
}
@@ -99,11 +87,10 @@ func BenchmarkSchemaLoad(b *testing.B) {
}
func BenchmarkRoundTrip(b *testing.B) {
delegationJson := golden.Get(b, "new.dagjson")
privKey := didtest.PersonaAlice.PrivKey()
b.Run("via buffers", func(b *testing.B) {
p1, _ := delegation.FromDagJson(delegationJson)
p1, _ := delegation.FromDagJson(newDagJson)
cborBytes, _, _ := p1.ToSealed(privKey)
p2, _, _ := delegation.FromSealed(cborBytes)
@@ -112,7 +99,7 @@ func BenchmarkRoundTrip(b *testing.B) {
b.Run("FromDagJson", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_, _ = delegation.FromDagJson(delegationJson)
_, _ = delegation.FromDagJson(newDagJson)
}
})
@@ -139,7 +126,7 @@ func BenchmarkRoundTrip(b *testing.B) {
})
b.Run("via streaming", func(b *testing.B) {
p1, _ := delegation.FromDagJsonReader(bytes.NewReader(delegationJson))
p1, _ := delegation.FromDagJsonReader(bytes.NewReader(newDagJson))
cborBuf := &bytes.Buffer{}
_, _ = p1.ToSealedWriter(cborBuf, privKey)
cborBytes := cborBuf.Bytes()
@@ -149,7 +136,7 @@ func BenchmarkRoundTrip(b *testing.B) {
b.Run("FromDagJsonReader", func(b *testing.B) {
b.ReportAllocs()
reader := bytes.NewReader(delegationJson)
reader := bytes.NewReader(newDagJson)
for i := 0; i < b.N; i++ {
_, _ = reader.Seek(0, 0)
_, _ = delegation.FromDagJsonReader(reader)

View File

@@ -0,0 +1,32 @@
{
"version": "1.0.0-rc.1",
"comments": "Principals private keys encoded as base64pad(varint(0x1300) + privateKey) and all other binary fields are encoded as base64pad.",
"principals": {
"carol": "gCZC43QGw7ZvYQuKTtBwBy+tdjYrKf0hXU3dd+J0HON5dw==",
"bob": "gCZfj9+RzU2U518TMBNK/fjdGQz34sB4iKE6z+9lQDpCIQ==",
"alice": "gCa9UfZv+yI5/rvUIt21DaGI7EZJlzFO1uDc5AyJ30c6/w=="
},
"valid": [
{
"name": "basic delegation bob > carol",
"token": "glhAd7jvZs44lTWmjSG/PWBRXvAdJA6Pq0fj86WQOVBYSw3fLrpjF7OMvjUlTynZZblPHzFsiBeBlUqtbCAHvhppCaJhaEg0Ae0B7QETcXN1Y2FuL2RsZ0AxLjAuMC1yYy4xp2NhdWR4OGRpZDprZXk6ejZNa21KY2VWb1FTSHM0NWNSZUVYb0x0V20xd29zQ0c4Ukx4Zkt3aHhvcXpvVGtDY2NtZGgvYWNjb3VudGNleHAaaIIMsWNpc3N4OGRpZDprZXk6ejZNa21UOWo2ZlZacXpYVjh1MndWVlN1NDlnWVNSWUdTUW5kdVdYRjZmb0FKcnF6Y3BvbIBjc3VieDhkaWQ6a2V5Ono2TWttVDlqNmZWWnF6WFY4dTJ3VlZTdTQ5Z1lTUllHU1FuZHVXWEY2Zm9BSnJxemVub25jZUwnbSv2keQn/Kg2KsM=",
"cid": "bafyreifqsojs54lpxxyx5xfqxiwkc4paglcyqd7vjzrcyapxi557extz6m",
"envelope": {
"payload": {
"iss": "did:key:z6MkmT9j6fVZqzXV8u2wVVSu49gYSRYGSQnduWXF6foAJrqz",
"aud": "did:key:z6MkmJceVoQSHs45cReEXoLtWm1wosCG8RLxfKwhxoqzoTkC",
"sub": "did:key:z6MkmT9j6fVZqzXV8u2wVVSu49gYSRYGSQnduWXF6foAJrqz",
"cmd": "/account",
"pol": [],
"exp": 1753353393,
"nonce": "J20r9pHkJ/yoNirD"
},
"signature": "d7jvZs44lTWmjSG/PWBRXvAdJA6Pq0fj86WQOVBYSw3fLrpjF7OMvjUlTynZZblPHzFsiBeBlUqtbCAHvhppCQ==",
"alg": "Ed25519",
"enc": "DAG-CBOR",
"spec": "dlg",
"version": "1.0.0-rc.1"
}
}
]
}

View File

@@ -1 +1 @@
[{"/":{"bytes":"YJsl8EMLnXSFE/nKKjMxz9bHHo+Y7QeLEzukEzW1TB+m53TTiY1aOt+qUO8JaTcOKsOHt/a4Vn+YiOd5CkLdAQ"}},{"h":{"/":{"bytes":"NO0BcQ"}},"ucan/dlg@1.0.0-rc.1":{"aud":"did:key:z6MkvJPmEZZYbgiw1ouT1oouTsTFBHJSts9ophVsNgcRmYxU","cmd":"/foo/bar","exp":7258118400,"iss":"did:key:z6Mkuukk2skDXLQn7NK3Eh9jMndYfvDBxxktgpidJAqb7M3p","meta":{"bar":"barr","foo":"fooo"},"nonce":{"/":{"bytes":"NnJvRGhHaTBraU5yaVFBejdKM2QrYk9lb0kvdGo4RU5pa21RTmJ0am5EMA"}},"pol":[["==",".status","draft"],["all",".reviewer",["like",".email","*@example.com"]],["any",".tags",["or",[["==",".","news"],["==",".","press"]]]]],"sub":"did:key:z6Mkgupchh5HwuHahS7YsyE8bLua1Mr8p2iKNRhyvSvRAs9n"}}]
[{"/":{"bytes":"7Df/QlkgvQ/j1sr2NUFryQbTxo16rsOPfDPX8evBmA0hV6Omv+sScM8HC30KHr/kXCl+DzxDg+/EOwiZ9ApNBQ"}},{"h":{"/":{"bytes":"NAHtAe0BE3E"}},"ucan/dlg@1.0.0-rc.1":{"aud":"did:key:z6Mkf4WtCwPDtamsZvBJA4eSVcE7vZuRPy5Skm4HaoQv81i1","cmd":"/foo/bar","exp":7258118400,"iss":"did:key:z6MknUz1mSj4pvS6aUUHekCHdUPv7HBhDyDBZQ2W3Vujc5qC","meta":{"bar":"barr","foo":"fooo"},"nonce":{"/":{"bytes":"NnJvRGhHaTBraU5yaVFBejdKM2QrYk9lb0kvdGo4RU5pa21RTmJ0am5EMA"}},"pol":[["==",".status","draft"],["all",".reviewer",["like",".email","*@example.com"]],["any",".tags",["or",[["==",".","news"],["==",".","press"]]]]],"sub":"did:key:z6MkjWFU8HtfMquWn5MEQ9r22zWqyCN1vazGw6g6pzciziNV"}}]

View File

@@ -1 +1 @@
[{"/":{"bytes":"i3YkPDvNSU4V8XYEluZhLH0b+NDcW/6+PtPSUHC17cmXXqgelG0K4EzWQQkS9UsYCHfkZSCn9NjGSXYMMFhaAQ"}},{"h":{"/":{"bytes":"NO0BcQ"}},"ucan/dlg@1.0.0-rc.1":{"aud":"did:key:z6MkvJPmEZZYbgiw1ouT1oouTsTFBHJSts9ophVsNgcRmYxU","cmd":"/foo/bar","exp":7258118400,"iss":"did:key:z6Mkuukk2skDXLQn7NK3Eh9jMndYfvDBxxktgpidJAqb7M3p","meta":{"bar":"barr","foo":"fooo"},"nonce":{"/":{"bytes":"NnJvRGhHaTBraU5yaVFBejdKM2QrYk9lb0kvdGo4RU5pa21RTmJ0am5EMA"}},"pol":[["==",".status","draft"],["all",".reviewer",["like",".email","*@example.com"]],["any",".tags",["or",[["==",".","news"],["==",".","press"]]]]]}}]
[{"/":{"bytes":"pcdEo4gSPlBWE1kQUUjFOQNRLvXDw6BTLmgoIrU/o1JCAeSYiiIQFrHB1KIm0phZfMHqp5O6k6QxHuldxUARBQ"}},{"h":{"/":{"bytes":"NAHtAe0BE3E"}},"ucan/dlg@1.0.0-rc.1":{"aud":"did:key:z6Mkf4WtCwPDtamsZvBJA4eSVcE7vZuRPy5Skm4HaoQv81i1","cmd":"/foo/bar","exp":7258118400,"iss":"did:key:z6MknUz1mSj4pvS6aUUHekCHdUPv7HBhDyDBZQ2W3Vujc5qC","meta":{"bar":"barr","foo":"fooo"},"nonce":{"/":{"bytes":"NnJvRGhHaTBraU5yaVFBejdKM2QrYk9lb0kvdGo4RU5pa21RTmJ0am5EMA"}},"pol":[["==",".status","draft"],["all",".reviewer",["like",".email","*@example.com"]],["any",".tags",["or",[["==",".","news"],["==",".","press"]]]]]}}]

View File

@@ -1 +1 @@
[{"/":{"bytes":"BBabgnWqd+cjwG1td0w9BudNocmUwoR89RMZTqZHk3osCXEI/bOkko0zTvlusaE4EMBBeSzZDKzjvunLBfdiBg"}},{"h":{"/":{"bytes":"NO0BcQ"}},"ucan/dlg@1.0.0-rc.1":{"aud":"did:key:z6MkvJPmEZZYbgiw1ouT1oouTsTFBHJSts9ophVsNgcRmYxU","cmd":"/foo/bar","exp":7258118400,"iss":"did:key:z6Mkuukk2skDXLQn7NK3Eh9jMndYfvDBxxktgpidJAqb7M3p","meta":{"bar":"barr","foo":"fooo"},"nonce":{"/":{"bytes":"NnJvRGhHaTBraU5yaVFBejdKM2QrYk9lb0kvdGo4RU5pa21RTmJ0am5EMA"}},"pol":[["==",".status","draft"],["all",".reviewer",["like",".email","*@example.com"]],["any",".tags",["or",[["==",".","news"],["==",".","press"]]]]],"sub":"did:key:z6Mkuukk2skDXLQn7NK3Eh9jMndYfvDBxxktgpidJAqb7M3p"}}]
[{"/":{"bytes":"jS5WzBU0JybWoQAJjJTgxke5U7vbwOJTYbe3bipYbmhz3Lcrl1B/68dK4xhWSv6wc3zZqXFJ7/Kw2jDLCOZWDA"}},{"h":{"/":{"bytes":"NAHtAe0BE3E"}},"ucan/dlg@1.0.0-rc.1":{"aud":"did:key:z6Mkf4WtCwPDtamsZvBJA4eSVcE7vZuRPy5Skm4HaoQv81i1","cmd":"/foo/bar","exp":7258118400,"iss":"did:key:z6MknUz1mSj4pvS6aUUHekCHdUPv7HBhDyDBZQ2W3Vujc5qC","meta":{"bar":"barr","foo":"fooo"},"nonce":{"/":{"bytes":"NnJvRGhHaTBraU5yaVFBejdKM2QrYk9lb0kvdGo4RU5pa21RTmJ0am5EMA"}},"pol":[["==",".status","draft"],["all",".reviewer",["like",".email","*@example.com"]],["any",".tags",["or",[["==",".","news"],["==",".","press"]]]]],"sub":"did:key:z6MknUz1mSj4pvS6aUUHekCHdUPv7HBhDyDBZQ2W3Vujc5qC"}}]

View File

@@ -16,7 +16,7 @@ type Loader interface {
GetDelegation(cid cid.Cid) (*Token, error)
}
// Bundle carries together a decoded delegation with its Cid and raw signed data.
// Bundle carries together a decoded token with its Cid and raw signed data.
type Bundle struct {
Cid cid.Cid
Decoded *Token

View File

@@ -4,9 +4,9 @@ import (
"io"
"time"
"github.com/MetaMask/go-did-it/crypto"
"github.com/ipfs/go-cid"
"github.com/ipld/go-ipld-prime/codec"
"github.com/libp2p/go-libp2p/core/crypto"
)
type Token interface {
@@ -15,7 +15,7 @@ type Token interface {
// IsValidNow verifies that the token can be used at the current time, based on expiration or "not before" fields.
// This does NOT do any other kind of verifications.
IsValidNow() bool
// IsValidNow verifies that the token can be used at the given time, based on expiration or "not before" fields.
// IsValidAt verifies that the token can be used at the given time, based on expiration or "not before" fields.
// This does NOT do any other kind of verifications.
IsValidAt(t time.Time) bool
}
@@ -23,19 +23,26 @@ type Token interface {
type Marshaller interface {
// ToSealed wraps the token in an envelope, generates the signature, encodes
// the result to DAG-CBOR and calculates the CID of the resulting binary data.
ToSealed(privKey crypto.PrivKey) ([]byte, cid.Cid, error)
ToSealed(privKey crypto.PrivateKeySigningBytes) ([]byte, cid.Cid, error)
// ToSealedWriter is the same as ToSealed but accepts an io.Writer.
ToSealedWriter(w io.Writer, privKey crypto.PrivKey) (cid.Cid, error)
ToSealedWriter(w io.Writer, privKey crypto.PrivateKeySigningBytes) (cid.Cid, error)
// Encode marshals a Token to the format specified by the provided codec.Encoder.
Encode(privKey crypto.PrivKey, encFn codec.Encoder) ([]byte, error)
Encode(privKey crypto.PrivateKeySigningBytes, encFn codec.Encoder) ([]byte, error)
// EncodeWriter is the same as Encode, but accepts an io.Writer.
EncodeWriter(w io.Writer, privKey crypto.PrivKey, encFn codec.Encoder) error
EncodeWriter(w io.Writer, privKey crypto.PrivateKeySigningBytes, encFn codec.Encoder) error
// ToDagCbor marshals the Token to the DAG-CBOR format.
ToDagCbor(privKey crypto.PrivKey) ([]byte, error)
ToDagCbor(privKey crypto.PrivateKeySigningBytes) ([]byte, error)
// ToDagCborWriter is the same as ToDagCbor, but it accepts an io.Writer.
ToDagCborWriter(w io.Writer, privKey crypto.PrivKey) error
ToDagCborWriter(w io.Writer, privKey crypto.PrivateKeySigningBytes) error
// ToDagJson marshals the Token to the DAG-JSON format.
ToDagJson(privKey crypto.PrivKey) ([]byte, error)
ToDagJson(privKey crypto.PrivateKeySigningBytes) ([]byte, error)
// ToDagJsonWriter is the same as ToDagJson, but it accepts an io.Writer.
ToDagJsonWriter(w io.Writer, privKey crypto.PrivKey) error
ToDagJsonWriter(w io.Writer, privKey crypto.PrivateKeySigningBytes) error
}
// Bundle carries together a decoded token with its Cid and raw signed data.
type Bundle struct {
Cid cid.Cid
Decoded Token
Sealed []byte
}

View File

@@ -9,7 +9,6 @@ import (
"github.com/multiformats/go-multihash"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gotest.tools/v3/golden"
"github.com/ucan-wg/go-ucan/token/internal/envelope"
)
@@ -17,11 +16,11 @@ import (
func TestCidFromBytes(t *testing.T) {
t.Parallel()
expData := golden.Get(t, "example.dagcbor")
expData := exampleDagCbor
expHash, err := multihash.Sum(expData, uint64(multicodec.Sha2_256), -1)
require.NoError(t, err)
data, err := envelope.ToDagCbor(examplePrivKey(t), newExample(t))
data, err := envelope.ToDagCbor(examplePrivKey(t), newExample())
require.NoError(t, err)
id, err := envelope.CIDFromBytes(data)

View File

@@ -7,6 +7,8 @@ import (
"sync"
"testing"
"github.com/MetaMask/go-did-it/crypto"
"github.com/MetaMask/go-did-it/crypto/ed25519"
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/codec/dagcbor"
"github.com/ipld/go-ipld-prime/datamodel"
@@ -14,32 +16,30 @@ import (
"github.com/ipld/go-ipld-prime/node/basicnode"
"github.com/ipld/go-ipld-prime/node/bindnode"
"github.com/ipld/go-ipld-prime/schema"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/stretchr/testify/require"
"gotest.tools/v3/golden"
"github.com/ucan-wg/go-ucan/token/internal/envelope"
)
const (
exampleCID = "zdpuAyw6R5HvKSPzztuzXNYFx3ZGoMHMuAsXL6u3xLGQriRXQ"
exampleDID = "did:key:z6MkpuK2Amsu1RqcLGgmHHQHhvmeXCCBVsM4XFSg2cCyg4Nh"
exampleCID = "zdpuAn4jksvc1gc9PLDqHw2NoFq8CBkRVTTo2xFuW2JUPS5DY"
exampleDID = "did:key:z6MkuqvEtTW9L1E91CY3GmL83muetLAA2h8A5fUHjJgqq2Ab"
exampleGreeting = "world"
examplePrivKeyCfg = "CAESQP9v2uqECTuIi45dyg3znQvsryvf2IXmOF/6aws6aCehm0FVrj0zHR5RZSDxWNjcpcJqsGym3sjCungX9Zt5oA4="
exampleSignatureStr = "PZV6A2aI7n+MlyADqcqmWhkuyNrgUCDz+qSLSnI9bpasOwOhKUTx95m5Nu5CO/INa1LqzHGioD9+PVf6qdtTBg"
examplePrivKeyB64 = "V4hh1lcFV43Y6vyOBEVOFTwl1XS/DR0F/kYcz5i6W/DkrUTG8yx09lOwSf36NCHPKSFYv/T1R3WKjNfndgVucA=="
exampleTag = "ucan/example@v1.0.0-rc.1"
exampleTypeName = "Example"
exampleVarsigHeaderStr = "NO0BcQ"
invalidSignatureStr = "PZV6A2aI7n+MlyADqcqmWhkuyNrgUCDz+qSLSnI9bpasOwOhKUTx95m5Nu5CO/INa1LqzHGioD9+PVf6qdtTBK"
exampleDAGCBORFilename = "example.dagcbor"
exampleDAGJSONFilename = "example.dagjson"
)
//go:embed testdata/example.ipldsch
var schemaBytes []byte
//go:embed testdata/example.dagcbor
var exampleDagCbor []byte
//go:embed testdata/example.dagjson
var exampleDagJson []byte
var (
once sync.Once
ts *schema.TypeSystem
@@ -59,7 +59,7 @@ func mustLoadSchema() *schema.TypeSystem {
}
func exampleType() schema.Type {
return mustLoadSchema().TypeByName(exampleTypeName)
return mustLoadSchema().TypeByName("Example")
}
var _ envelope.Tokener = (*Example)(nil)
@@ -69,9 +69,7 @@ type Example struct {
Issuer string
}
func newExample(t *testing.T) *Example {
t.Helper()
func newExample() *Example {
return &Example{
Hello: exampleGreeting,
Issuer: exampleDID,
@@ -86,45 +84,30 @@ func (*Example) Tag() string {
return exampleTag
}
func exampleGoldenNode(t *testing.T) datamodel.Node {
func examplePrivKey(t *testing.T) crypto.PrivateKeySigningBytes {
t.Helper()
cbor := golden.Get(t, exampleDAGCBORFilename)
node, err := ipld.Decode(cbor, dagcbor.Decode)
privBytes, err := base64.StdEncoding.DecodeString(examplePrivKeyB64)
require.NoError(t, err)
return node
}
func examplePrivKey(t *testing.T) crypto.PrivKey {
t.Helper()
privKeyEnc, err := crypto.ConfigDecodeKey(examplePrivKeyCfg)
require.NoError(t, err)
privKey, err := crypto.UnmarshalPrivateKey(privKeyEnc)
privKey, err := ed25519.PrivateKeyFromBytes(privBytes)
require.NoError(t, err)
return privKey
}
func exampleSignature(t *testing.T) []byte {
t.Helper()
sig, err := base64.RawStdEncoding.DecodeString(exampleSignatureStr)
require.NoError(t, err)
return sig
}
func invalidNodeFromGolden(t *testing.T) datamodel.Node {
// nodeWithInvalidSignature creates an IPLD node of a token, with an invalid signature
func nodeWithInvalidSignature(t *testing.T) datamodel.Node {
t.Helper()
invalidSig, err := base64.RawStdEncoding.DecodeString(invalidSignatureStr)
require.NoError(t, err)
envelNode := exampleGoldenNode(t)
cbor := exampleDagCbor
envelNode, err := ipld.Decode(cbor, dagcbor.Decode)
require.NoError(t, err)
sigPayloadNode, err := envelNode.LookupByIndex(1)
require.NoError(t, err)

View File

@@ -3,7 +3,7 @@
// a verified [TokenPayload].
//
// Encoding functions in this package require a private key as a
// parameter so the VarsigHeader can be set and so that a
// parameter so the VarsigBytes can be set and so that a
// cryptographic signature can be generated.
//
// Decoding functions in this package likewise perform the signature
@@ -40,10 +40,10 @@ import (
"github.com/ipld/go-ipld-prime/node/basicnode"
"github.com/ipld/go-ipld-prime/node/bindnode"
"github.com/ipld/go-ipld-prime/schema"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/ucan-wg/go-varsig"
"github.com/ucan-wg/go-ucan/did"
"github.com/ucan-wg/go-ucan/token/internal/varsig"
"github.com/MetaMask/go-did-it"
"github.com/MetaMask/go-did-it/crypto"
)
const (
@@ -70,56 +70,56 @@ type Tokener interface {
//
// An error is returned if the conversion fails, or if the resulting
// Tokener is invalid.
func Decode[T Tokener](b []byte, decFn codec.Decoder) (T, error) {
func Decode[T Tokener](b []byte, decFn codec.Decoder, resolvOpts ...did.ResolutionOption) (T, error) {
node, err := ipld.Decode(b, decFn)
if err != nil {
return *new(T), err
}
return FromIPLD[T](node)
return FromIPLD[T](node, resolvOpts...)
}
// DecodeReader is the same as Decode, but accept an io.Reader.
func DecodeReader[T Tokener](r io.Reader, decFn codec.Decoder) (T, error) {
func DecodeReader[T Tokener](r io.Reader, decFn codec.Decoder, resolvOpts ...did.ResolutionOption) (T, error) {
node, err := ipld.DecodeStreaming(r, decFn)
if err != nil {
return *new(T), err
}
return FromIPLD[T](node)
return FromIPLD[T](node, resolvOpts...)
}
// FromDagCbor unmarshals the input data into a Tokener.
//
// An error is returned if the conversion fails, or if the resulting
// Tokener is invalid.
func FromDagCbor[T Tokener](b []byte) (T, error) {
return Decode[T](b, dagcbor.Decode)
func FromDagCbor[T Tokener](b []byte, resolvOpts ...did.ResolutionOption) (T, error) {
return Decode[T](b, dagcbor.Decode, resolvOpts...)
}
// FromDagCborReader is the same as FromDagCbor, but accept an io.Reader.
func FromDagCborReader[T Tokener](r io.Reader) (T, error) {
return DecodeReader[T](r, dagcbor.Decode)
func FromDagCborReader[T Tokener](r io.Reader, resolvOpts ...did.ResolutionOption) (T, error) {
return DecodeReader[T](r, dagcbor.Decode, resolvOpts...)
}
// FromDagJson unmarshals the input data into a Tokener.
//
// An error is returned if the conversion fails, or if the resulting
// Tokener is invalid.
func FromDagJson[T Tokener](b []byte) (T, error) {
return Decode[T](b, dagjson.Decode)
func FromDagJson[T Tokener](b []byte, resolvOpts ...did.ResolutionOption) (T, error) {
return Decode[T](b, dagjson.Decode, resolvOpts...)
}
// FromDagJsonReader is the same as FromDagJson, but accept an io.Reader.
func FromDagJsonReader[T Tokener](r io.Reader) (T, error) {
return DecodeReader[T](r, dagjson.Decode)
func FromDagJsonReader[T Tokener](r io.Reader, resolvOpts ...did.ResolutionOption) (T, error) {
return DecodeReader[T](r, dagjson.Decode, resolvOpts...)
}
// FromIPLD unwraps a Tokener from the provided IPLD datamodel.Node.
//
// An error is returned if the conversion fails, or if the resulting
// Tokener is invalid.
func FromIPLD[T Tokener](node datamodel.Node) (T, error) {
func FromIPLD[T Tokener](node datamodel.Node, resolvOpts ...did.ResolutionOption) (T, error) {
zero := *new(T)
info, err := Inspect(node)
@@ -132,7 +132,7 @@ func FromIPLD[T Tokener](node datamodel.Node) (T, error) {
}
// This needs to be done before converting this node to its schema
// representation (afterwards, the field might be renamed os it's safer
// representation (afterwards, the field might be renamed, so it's safer
// to use the wire name).
issuerNode, err := info.tokenPayloadNode.LookupByString("iss")
if err != nil {
@@ -162,7 +162,7 @@ func FromIPLD[T Tokener](node datamodel.Node) (T, error) {
}
// Check that the issuer's DID contains a public key with a type that
// matches the VarsigHeader and then verify the SigPayload.
// matches the VarsigBytes and then verify the SigPayload.
issuer, err := issuerNode.AsString()
if err != nil {
return zero, err
@@ -173,28 +173,35 @@ func FromIPLD[T Tokener](node datamodel.Node) (T, error) {
return zero, err
}
issuerPubKey, err := issuerDID.PubKey()
issuerDoc, err := issuerDID.Document(resolvOpts...)
if err != nil {
return zero, err
}
issuerVarsigHeader, err := varsig.Encode(issuerPubKey.Type())
vsig, err := varsig.Decode(info.VarsigBytes)
if err != nil {
return zero, err
return zero, fmt.Errorf("failed to decode varsig: %w", err)
}
if string(info.VarsigHeader) != string(issuerVarsigHeader) {
return zero, errors.New("the VarsigHeader key type doesn't match the issuer's key type")
}
var data []byte
switch vsig.PayloadEncoding() {
case varsig.PayloadEncodingDAGCBOR:
// TODO: can we use the already serialized CBOR data here, instead of encoding again the payload?
data, err := ipld.Encode(info.sigPayloadNode, dagcbor.Encode)
data, err = ipld.Encode(info.sigPayloadNode, dagcbor.Encode)
case varsig.PayloadEncodingDAGJSON:
data, err = ipld.Encode(info.sigPayloadNode, dagjson.Encode)
default:
return zero, errors.New("unsupported payload encoding")
}
if err != nil {
return zero, err
}
ok, err = issuerPubKey.Verify(data, info.Signature)
if err != nil || !ok {
// TODO: use CapabilityDelegation() or CapabilityInvocation()
ok, _ = did.TryAllVerifyBytes(issuerDoc.CapabilityDelegation(), data, info.Signature, crypto.WithVarsig(vsig))
if !ok {
return zero, errors.New("failed to verify the token's signature")
}
@@ -203,7 +210,7 @@ func FromIPLD[T Tokener](node datamodel.Node) (T, error) {
// Encode marshals a Tokener to the format specified by the provided
// codec.Encoder.
func Encode(privKey crypto.PrivKey, token Tokener, encFn codec.Encoder) ([]byte, error) {
func Encode(privKey crypto.PrivateKeySigningBytes, token Tokener, encFn codec.Encoder) ([]byte, error) {
node, err := ToIPLD(privKey, token)
if err != nil {
return nil, err
@@ -214,7 +221,7 @@ func Encode(privKey crypto.PrivKey, token Tokener, encFn codec.Encoder) ([]byte,
// EncodeWriter is the same as Encode but outputs to an io.Writer instead
// of encoding into a []byte.
func EncodeWriter(w io.Writer, privKey crypto.PrivKey, token Tokener, encFn codec.Encoder) error {
func EncodeWriter(w io.Writer, privKey crypto.PrivateKeySigningBytes, token Tokener, encFn codec.Encoder) error {
node, err := ToIPLD(privKey, token)
if err != nil {
return err
@@ -224,38 +231,36 @@ func EncodeWriter(w io.Writer, privKey crypto.PrivKey, token Tokener, encFn code
}
// ToDagCbor marshals the Tokener to the DAG-CBOR format.
func ToDagCbor(privKey crypto.PrivKey, token Tokener) ([]byte, error) {
func ToDagCbor(privKey crypto.PrivateKeySigningBytes, token Tokener) ([]byte, error) {
return Encode(privKey, token, dagcbor.Encode)
}
// ToDagCborWriter is the same as ToDagCbor but outputs to an io.Writer
// instead of encoding into a []byte.
func ToDagCborWriter(w io.Writer, privKey crypto.PrivKey, token Tokener) error {
func ToDagCborWriter(w io.Writer, privKey crypto.PrivateKeySigningBytes, token Tokener) error {
return EncodeWriter(w, privKey, token, dagcbor.Encode)
}
// ToDagJson marshals the Tokener to the DAG-JSON format.
func ToDagJson(privKey crypto.PrivKey, token Tokener) ([]byte, error) {
func ToDagJson(privKey crypto.PrivateKeySigningBytes, token Tokener) ([]byte, error) {
return Encode(privKey, token, dagjson.Encode)
}
// ToDagJsonWriter is the same as ToDagJson but outputs to an io.Writer
// instead of encoding into a []byte.
func ToDagJsonWriter(w io.Writer, privKey crypto.PrivKey, token Tokener) error {
func ToDagJsonWriter(w io.Writer, privKey crypto.PrivateKeySigningBytes, token Tokener) error {
return EncodeWriter(w, privKey, token, dagjson.Encode)
}
// ToIPLD wraps the Tokener in an IPLD datamodel.Node.
func ToIPLD(privKey crypto.PrivKey, token Tokener) (datamodel.Node, error) {
func ToIPLD(privKey crypto.PrivateKeySigningBytes, token Tokener) (datamodel.Node, error) {
tokenPayloadNode := bindnode.Wrap(token, token.Prototype().Type()).Representation()
varsigHeader, err := varsig.Encode(privKey.Type())
if err != nil {
return nil, err
}
opts := []crypto.SigningOption{crypto.WithPayloadEncoding(varsig.PayloadEncodingDAGCBOR)}
vsig := privKey.Varsig(opts...)
sigPayloadNode, err := qp.BuildMap(basicnode.Prototype.Any, 2, func(ma datamodel.MapAssembler) {
qp.MapEntry(ma, VarsigHeaderKey, qp.Bytes(varsigHeader))
qp.MapEntry(ma, VarsigHeaderKey, qp.Bytes(vsig.Encode()))
qp.MapEntry(ma, token.Tag(), qp.Node(tokenPayloadNode))
})
@@ -264,7 +269,7 @@ func ToIPLD(privKey crypto.PrivKey, token Tokener) (datamodel.Node, error) {
return nil, err
}
signature, err := privKey.Sign(data)
signature, err := privKey.SignToBytes(data, opts...)
if err != nil {
return nil, err
}
@@ -315,7 +320,7 @@ func FindTag(node datamodel.Node) (string, error) {
type Info struct {
Tag string
Signature []byte
VarsigHeader []byte
VarsigBytes []byte
sigPayloadNode datamodel.Node // private, we don't want to expose that
tokenPayloadNode datamodel.Node // private, we don't want to expose that
}
@@ -367,7 +372,7 @@ func Inspect(node datamodel.Node) (Info, error) {
switch {
case key == VarsigHeaderKey:
foundVarsigHeader = true
res.VarsigHeader, err = v.AsBytes()
res.VarsigBytes, err = v.AsBytes()
if err != nil {
return Info{}, err
}

View File

@@ -3,15 +3,16 @@ package envelope_test
import (
"bytes"
"crypto/sha256"
_ "embed"
"encoding/base64"
"os"
"testing"
_ "github.com/MetaMask/go-did-it/verifiers/did-key"
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/codec/dagcbor"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gotest.tools/v3/golden"
"github.com/ucan-wg/go-ucan/token/internal/envelope"
)
@@ -22,9 +23,7 @@ func TestDecode(t *testing.T) {
t.Run("via FromDagCbor", func(t *testing.T) {
t.Parallel()
data := golden.Get(t, "example.dagcbor")
tkn, err := envelope.FromDagCbor[*Example](data)
tkn, err := envelope.FromDagCbor[*Example](exampleDagCbor)
require.NoError(t, err)
assert.Equal(t, exampleGreeting, tkn.Hello)
assert.Equal(t, exampleDID, tkn.Issuer)
@@ -33,9 +32,7 @@ func TestDecode(t *testing.T) {
t.Run("via FromDagJson", func(t *testing.T) {
t.Parallel()
data := golden.Get(t, "example.dagjson")
tkn, err := envelope.FromDagJson[*Example](data)
tkn, err := envelope.FromDagJson[*Example](exampleDagJson)
require.NoError(t, err)
assert.Equal(t, exampleGreeting, tkn.Hello)
assert.Equal(t, exampleDID, tkn.Issuer)
@@ -48,17 +45,17 @@ func TestEncode(t *testing.T) {
t.Run("via ToDagCbor", func(t *testing.T) {
t.Parallel()
data, err := envelope.ToDagCbor(examplePrivKey(t), newExample(t))
data, err := envelope.ToDagCbor(examplePrivKey(t), newExample())
require.NoError(t, err)
golden.AssertBytes(t, data, exampleDAGCBORFilename)
require.Equal(t, exampleDagCbor, data)
})
t.Run("via ToDagJson", func(t *testing.T) {
t.Parallel()
data, err := envelope.ToDagJson(examplePrivKey(t), newExample(t))
data, err := envelope.ToDagJson(examplePrivKey(t), newExample())
require.NoError(t, err)
golden.Assert(t, string(data), exampleDAGJSONFilename)
require.Equal(t, exampleDagJson, data)
})
}
@@ -68,14 +65,14 @@ func TestRoundtrip(t *testing.T) {
t.Run("via FromDagCbor/ToDagCbor", func(t *testing.T) {
t.Parallel()
dataIn := golden.Get(t, exampleDAGCBORFilename)
dataIn := exampleDagCbor
tkn, err := envelope.FromDagCbor[*Example](dataIn)
require.NoError(t, err)
assert.Equal(t, exampleGreeting, tkn.Hello)
assert.Equal(t, exampleDID, tkn.Issuer)
dataOut, err := envelope.ToDagCbor(examplePrivKey(t), newExample(t))
dataOut, err := envelope.ToDagCbor(examplePrivKey(t), newExample())
require.NoError(t, err)
assert.Equal(t, dataIn, dataOut)
})
@@ -83,7 +80,7 @@ func TestRoundtrip(t *testing.T) {
t.Run("via FromDagCborReader/ToDagCborWriter", func(t *testing.T) {
t.Parallel()
data := golden.Get(t, exampleDAGCBORFilename)
data := exampleDagCbor
tkn, err := envelope.FromDagCborReader[*Example](bytes.NewReader(data))
require.NoError(t, err)
@@ -91,21 +88,21 @@ func TestRoundtrip(t *testing.T) {
assert.Equal(t, exampleDID, tkn.Issuer)
w := &bytes.Buffer{}
require.NoError(t, envelope.ToDagCborWriter(w, examplePrivKey(t), newExample(t)))
require.NoError(t, envelope.ToDagCborWriter(w, examplePrivKey(t), newExample()))
assert.Equal(t, data, w.Bytes())
})
t.Run("via FromDagJson/ToDagJson", func(t *testing.T) {
t.Parallel()
dataIn := golden.Get(t, exampleDAGJSONFilename)
dataIn := exampleDagJson
tkn, err := envelope.FromDagJson[*Example](dataIn)
require.NoError(t, err)
assert.Equal(t, exampleGreeting, tkn.Hello)
assert.Equal(t, exampleDID, tkn.Issuer)
dataOut, err := envelope.ToDagJson(examplePrivKey(t), newExample(t))
dataOut, err := envelope.ToDagJson(examplePrivKey(t), newExample())
require.NoError(t, err)
assert.Equal(t, dataIn, dataOut)
})
@@ -113,7 +110,7 @@ func TestRoundtrip(t *testing.T) {
t.Run("via FromDagJsonReader/ToDagJsonrWriter", func(t *testing.T) {
t.Parallel()
data := golden.Get(t, exampleDAGJSONFilename)
data := exampleDagJson
tkn, err := envelope.FromDagJsonReader[*Example](bytes.NewReader(data))
require.NoError(t, err)
@@ -121,7 +118,7 @@ func TestRoundtrip(t *testing.T) {
assert.Equal(t, exampleDID, tkn.Issuer)
w := &bytes.Buffer{}
require.NoError(t, envelope.ToDagJsonWriter(w, examplePrivKey(t), newExample(t)))
require.NoError(t, envelope.ToDagJsonWriter(w, examplePrivKey(t), newExample()))
assert.Equal(t, data, w.Bytes())
})
}
@@ -129,7 +126,7 @@ func TestRoundtrip(t *testing.T) {
func TestFromIPLD_with_invalid_signature(t *testing.T) {
t.Parallel()
node := invalidNodeFromGolden(t)
node := nodeWithInvalidSignature(t)
tkn, err := envelope.FromIPLD[*Example](node)
assert.Nil(t, tkn)
require.EqualError(t, err, "failed to verify the token's signature")
@@ -158,18 +155,17 @@ func TestHash(t *testing.T) {
func TestInspect(t *testing.T) {
t.Parallel()
data := golden.Get(t, "example.dagcbor")
node, err := ipld.Decode(data, dagcbor.Decode)
node, err := ipld.Decode(exampleDagCbor, dagcbor.Decode)
require.NoError(t, err)
expSig, err := base64.RawStdEncoding.DecodeString("fPqfwL3iFpbw9SvBiq0DIbUurv9o6c36R08tC/yslGrJcwV51ghzWahxdetpEf6T5LCszXX9I/K8khvnmAxjAg")
expSig, err := base64.RawStdEncoding.DecodeString("+xUwgl/5VZcTxx6iePmkrIaZAlxuelHTbeQ5lQIgIV3ZgHS+Jf5BUERB0fvmFfiIfa5A3yMPfEA/7rswYsRRCg")
require.NoError(t, err)
info, err := envelope.Inspect(node)
require.NoError(t, err)
assert.Equal(t, expSig, info.Signature)
assert.Equal(t, "ucan/example@v1.0.0-rc.1", info.Tag)
assert.Equal(t, []byte{0x34, 0xed, 0x1, 0x71}, info.VarsigHeader)
assert.Equal(t, []byte{0x34, 0x1, 0xed, 0x1, 0xed, 0x1, 0x13, 0x71}, info.VarsigBytes)
}
func FuzzInspect(f *testing.F) {

View File

@@ -1 +1,2 @@
X@|úŸÀ½â–ðõ+ÁŠ­!µ.®ÿhéÍúGO- ü¬”jÉssY¨quëiþ“ä°¬Íuý#ò¼’ç˜ c¢ahD4íqxucan/example@v1.0.0-rc.1¢cissx8did:key:z6MkpuK2Amsu1RqcLGgmHHQHhvmeXCCBVsM4XFSg2cCyg4Nhehelloeworld
X@û0_ùU—Ç¢xù¤¬†™\nzQÓmä9• !]Ù€t¾%þAPDAÑûæøˆ}®@ß#|@?î»0bÄQ
¢ahH4ííqxucan/example@v1.0.0-rc.1¢cissx8did:key:z6MkuqvEtTW9L1E91CY3GmL83muetLAA2h8A5fUHjJgqq2Abehelloeworld

View File

@@ -1 +1 @@
[{"/":{"bytes":"fPqfwL3iFpbw9SvBiq0DIbUurv9o6c36R08tC/yslGrJcwV51ghzWahxdetpEf6T5LCszXX9I/K8khvnmAxjAg"}},{"h":{"/":{"bytes":"NO0BcQ"}},"ucan/example@v1.0.0-rc.1":{"hello":"world","iss":"did:key:z6MkpuK2Amsu1RqcLGgmHHQHhvmeXCCBVsM4XFSg2cCyg4Nh"}}]
[{"/":{"bytes":"+xUwgl/5VZcTxx6iePmkrIaZAlxuelHTbeQ5lQIgIV3ZgHS+Jf5BUERB0fvmFfiIfa5A3yMPfEA/7rswYsRRCg"}},{"h":{"/":{"bytes":"NAHtAe0BE3E"}},"ucan/example@v1.0.0-rc.1":{"hello":"world","iss":"did:key:z6MkuqvEtTW9L1E91CY3GmL83muetLAA2h8A5fUHjJgqq2Ab"}}]

View File

@@ -4,13 +4,14 @@ import (
"fmt"
"time"
"github.com/ucan-wg/go-ucan/did"
"github.com/MetaMask/go-did-it"
"github.com/ucan-wg/go-ucan/pkg/policy/limits"
)
func OptionalDID(s *string) (did.DID, error) {
if s == nil {
return did.Undef, nil
return nil, nil
}
return did.Parse(*s)
}

View File

@@ -4,6 +4,7 @@ import (
"testing"
"github.com/stretchr/testify/require"
"github.com/ucan-wg/go-ucan/pkg/policy/limits"
)

View File

@@ -1,133 +0,0 @@
// Package varsig implements the portion of the [varsig specification]
// that's needed for the UCAN [Envelope].
//
// While the [Envelope] specification has a field that's labelled
// "VarsigHeader", this field is actually the prefix, header and segments
// of the body excluding the signature itself (which is a different field
// in the [Envelope]).
//
// Given that [go-ucan] supports a limited number of public key types,
// and that the signature isn't part of the resulting field, the values
// that are used are constants. Note that for key types that are fully
// specified in the [did:key], the [VarsigHeader] field isn't technically
// needed and could theoretically conflict with the DID.
//
// Treating these values as constants has no impact when issuing or
// delegating tokens. When decoding tokens, simply matching the strings
// will allow us to detect errors but won't provide as much detail (e.g.
// we can't indicate that the signature was incorrectly generated from
// a DAG-JSON encoding.)
//
// [varsig specification]: https://github.com/ChainAgnostic/varsig
// [Envelope]:https://github.com/ucan-wg/spec#envelope
// [go-ucan]: https://github.com/ucan-wg/go-ucan
package varsig
import (
"encoding/binary"
"errors"
"fmt"
"github.com/libp2p/go-libp2p/core/crypto/pb"
"github.com/multiformats/go-multicodec"
)
const (
Prefix = 0x34
)
// ErrUnknownHeader is returned when it's not possible to decode the
// provided string into a libp2p public key type.
var ErrUnknownHeader = errors.New("could not decode unknown header")
// ErrUnknownKeyType is returned when value provided is not a valid
// libp2p public key type.
var ErrUnknownKeyType = errors.New("could not encode unsupported key type")
var (
decMap = headerToKeyType()
encMap = keyTypeToHeader()
)
// Decode returns either the pb.KeyType associated with the provided Header
// or an error.
//
// Currently, only the four key types supported by the [go-libp2p/core/crypto]
// library are supported.
//
// [go-libp2p/core/crypto]: github.com/libp2p/go-libp2p/core/crypto
func Decode(header []byte) (pb.KeyType, error) {
keyType, ok := decMap[string(header)]
if !ok {
return -1, fmt.Errorf("%w: %s", ErrUnknownHeader, header)
}
return keyType, nil
}
// Encode returns either the header associated with the provided pb.KeyType
// or an error indicating the header was unknown.
//
// Currently, only the four key types supported by the [go-libp2p/core/crypto]
// library are supported.
//
// [go-libp2p/core/crypto]: github.com/libp2p/go-libp2p/core/crypto
func Encode(keyType pb.KeyType) ([]byte, error) {
header, ok := encMap[keyType]
if !ok {
return nil, fmt.Errorf("%w: %s", ErrUnknownKeyType, keyType.String())
}
return []byte(header), nil
}
func keyTypeToHeader() map[pb.KeyType]string {
const rsaSigLen = 0x100
return map[pb.KeyType]string{
pb.KeyType_RSA: header(
Prefix,
multicodec.RsaPub,
multicodec.Sha2_256,
rsaSigLen,
multicodec.DagCbor,
),
pb.KeyType_Ed25519: header(
Prefix,
multicodec.Ed25519Pub,
multicodec.DagCbor,
),
pb.KeyType_Secp256k1: header(
Prefix,
multicodec.Secp256k1Pub,
multicodec.Sha2_256,
multicodec.DagCbor,
),
pb.KeyType_ECDSA: header(
Prefix,
multicodec.Es256,
multicodec.Sha2_256,
multicodec.DagCbor,
),
}
}
func headerToKeyType() map[string]pb.KeyType {
out := make(map[string]pb.KeyType, len(encMap))
for keyType, header := range encMap {
out[header] = keyType
}
return out
}
func header(vals ...multicodec.Code) string {
var buf []byte
for _, val := range vals {
buf = binary.AppendUvarint(buf, uint64(val))
}
return string(buf)
}

View File

@@ -1,51 +0,0 @@
package varsig_test
import (
"encoding/base64"
"fmt"
"testing"
"github.com/libp2p/go-libp2p/core/crypto/pb"
"github.com/stretchr/testify/assert"
"github.com/ucan-wg/go-ucan/token/internal/varsig"
)
func TestDecode(t *testing.T) {
t.Parallel()
notAHeader := base64.RawStdEncoding.EncodeToString([]byte("not a header"))
keyType, err := varsig.Decode([]byte(notAHeader))
assert.Equal(t, pb.KeyType(-1), keyType)
assert.ErrorIs(t, err, varsig.ErrUnknownHeader)
}
func ExampleDecode() {
hdr, err := base64.RawStdEncoding.DecodeString("NIUkEoACcQ")
if err != nil {
fmt.Println(err.Error())
return
}
keyType, _ := varsig.Decode(hdr)
fmt.Println(keyType.String())
// Output:
// RSA
}
func TestEncode(t *testing.T) {
t.Parallel()
header, err := varsig.Encode(pb.KeyType(99))
assert.Nil(t, header)
assert.ErrorIs(t, err, varsig.ErrUnknownKeyType)
}
func ExampleEncode() {
header, _ := varsig.Encode(pb.KeyType_RSA)
fmt.Println(base64.RawStdEncoding.EncodeToString(header))
// Output:
// NIUkEoACcQ
}

View File

@@ -4,13 +4,13 @@ import "errors"
// Loading errors
var (
// ErrMissingDelegation
// ErrMissingDelegation is returned when a loader can't find a delegation
ErrMissingDelegation = errors.New("loader missing delegation for proof chain")
)
// Time bound errors
var (
// ErrTokenExpired is returned if a token is invalid at execution time
// ErrTokenInvalidNow is returned if a token is invalid at execution time
ErrTokenInvalidNow = errors.New("token has expired")
)

View File

@@ -7,14 +7,15 @@ import (
"fmt"
"time"
"github.com/MetaMask/go-did-it"
didkeyctl "github.com/MetaMask/go-did-it/controller/did-key"
"github.com/MetaMask/go-did-it/crypto/ed25519"
"github.com/ipfs/go-cid"
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/codec/dagcbor"
"github.com/ipld/go-ipld-prime/codec/dagjson"
"github.com/ipld/go-ipld-prime/node/basicnode"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/ucan-wg/go-ucan/did"
"github.com/ucan-wg/go-ucan/pkg/command"
"github.com/ucan-wg/go-ucan/token/invocation"
)
@@ -34,7 +35,7 @@ func ExampleNew() {
invocation.WithMeta("env", "development"),
invocation.WithMeta("tags", meta["tags"]),
invocation.WithExpirationIn(time.Minute),
invocation.WithoutInvokedAt())
invocation.WithoutIssuedAt())
if err != nil {
fmt.Println("failed to create invocation:", err.Error())
@@ -60,18 +61,18 @@ func ExampleNew() {
fmt.Println(json)
// Expected CID and DAG-JSON output:
// CID: bafyreid2n5q45vk4osned7k5huocbe3mxbisonh5vujepqftc5ftr543ae
// CID: bafyreicgyuf6g7geoupyzpo3lgvyvsyhtc6tvnhiajkoo7lmy6woavkhra
// Token (pretty DAG-JSON):
// [
// {
// "/": {
// "bytes": "gvyL7kdSkgmaDpDU/Qj9ohRwxYLCHER52HFMSFEqQqEcQC9qr4JCPP1f/WybvGGuVzYiA0Hx4JO+ohNz8BxUAA"
// "bytes": "nWYKygq0TTooQGdQsfQWwMOCuX7+KYNRSyW8h4AcRoTIJHsYyG/mpU3iBhAdsAGhi8Brnm+/Z0tC2KoC/KUlDA"
// }
// },
// {
// "h": {
// "/": {
// "bytes": "NO0BcQ"
// "bytes": "NAHtAe0BE3E"
// }
// },
// "ucan/inv@1.0.0-rc.1": {
@@ -91,8 +92,8 @@ func ExampleNew() {
// "uri": "https://example.com/blog/posts"
// },
// "cmd": "/crud/create",
// "exp": 1729788921,
// "iss": "did:key:z6MkhniGGyP88eZrq2dpMvUPdS2RQMhTUAWzcu6kVGUvEtCJ",
// "exp": 1753965273,
// "iss": "did:key:z6MknZNRLJ8zD2x5QhFuPsXYKAJ8PJpCe76bC5p7bGZXC5HD",
// "meta": {
// "env": "development",
// "tags": [
@@ -103,7 +104,7 @@ func ExampleNew() {
// },
// "nonce": {
// "/": {
// "bytes": "2xXPoZwWln1TfXIp"
// "bytes": "y4kwaLuEHOPBUgrl"
// }
// },
// "prf": [
@@ -117,7 +118,7 @@ func ExampleNew() {
// "/": "bafyreibkb66tpo2ixqx3fe5hmekkbuasrod6olt5bwm5u5pi726mduuwlq"
// }
// ],
// "sub": "did:key:z6MktWuvPvBe5UyHnDGuEdw8aJ5qrhhwLG6jy7cQYM6ckP6P"
// "sub": "did:key:z6MkqEBN9zEGU9Euh9toLGFkTaSguXPavv55yS9m3VnwWeMW"
// }
// }
// ]
@@ -144,18 +145,22 @@ func prettyDAGJSON(data []byte) (string, error) {
return out.String(), nil
}
func setupExampleNew() (privKey crypto.PrivKey, iss, sub did.DID, cmd command.Command, args map[string]any, prf []cid.Cid, meta map[string]any, errs error) {
func setupExampleNew() (privKey ed25519.PrivateKey, iss, sub did.DID, cmd command.Command, args map[string]any, prf []cid.Cid, meta map[string]any, errs error) {
var err error
privKey, iss, err = did.GenerateEd25519()
_, privKey, err = ed25519.GenerateKeyPair()
if err != nil {
errs = errors.Join(errs, fmt.Errorf("failed to generate Issuer identity: %w", err))
errs = errors.Join(errs, fmt.Errorf("failed to generate Ed25519 keypair: %w", err))
return
}
iss = didkeyctl.FromPrivateKey(privKey)
_, sub, err = did.GenerateEd25519()
_, privKeySub, err := ed25519.GenerateKeyPair()
if err != nil {
errs = errors.Join(errs, fmt.Errorf("failed to generate Subject identity: %w", err))
errs = errors.Join(errs, fmt.Errorf("failed to generate Ed25519 keypair: %w", err))
return
}
sub = didkeyctl.FromPrivateKey(privKeySub)
cmd, err = command.Parse("/crud/create")
if err != nil {

View File

@@ -14,9 +14,9 @@ import (
"strings"
"time"
"github.com/MetaMask/go-did-it"
"github.com/ipfs/go-cid"
"github.com/ucan-wg/go-ucan/did"
"github.com/ucan-wg/go-ucan/pkg/args"
"github.com/ucan-wg/go-ucan/pkg/command"
"github.com/ucan-wg/go-ucan/pkg/meta"
@@ -51,7 +51,7 @@ type Token struct {
// The timestamp at which the Invocation becomes invalid
expiration *time.Time
// The timestamp at which the Invocation was created
invokedAt *time.Time
issuedAt *time.Time
// An optional CID of the Receipt that enqueued the Task
cause *cid.Cid
@@ -59,13 +59,16 @@ type Token struct {
// New creates an invocation Token with the provided options.
//
// The given proofs MUST be ordered from the leaf (matching the invocation) to
// the root delegation.
//
// If no nonce is provided, a random 12-byte nonce is generated. Use the
// WithNonce or WithEmptyNonce options to specify provide your own nonce
// or to leave the nonce empty respectively.
//
// If no invokedAt is provided, the current time is used. Use the
// WithInvokedAt or WithInvokedAtIn Options to specify a different time
// or the WithoutInvokedAt Option to clear the Token's invokedAt field.
// If no IssuedAt is provided, the current time is used. Use the
// IssuedAt or WithIssuedAtIn Options to specify a different time
// or the WithoutIssuedAt Option to clear the Token's IssuedAt field.
//
// With the exception of the WithMeta option, all others will overwrite
// the previous contents of their target field.
@@ -82,7 +85,7 @@ func New(iss did.DID, cmd command.Command, sub did.DID, prf []cid.Cid, opts ...O
proof: prf,
meta: meta.NewMeta(),
nonce: nil,
invokedAt: &iat,
issuedAt: &iat,
}
for _, opt := range opts {
@@ -106,10 +109,23 @@ func New(iss did.DID, cmd command.Command, sub did.DID, prf []cid.Cid, opts ...O
return &tkn, nil
}
// NewSelfSigned is similar to New, but self-signs the invocation, and therefore does not require a proof.
// It's similar to having an invocation with a delegation from the invoker to itself.
// This can be useful in some protocols where the invoker is the same as the subject, or to prove ownership of a resource.
//
// You can read it as "(Issuer - I) executes (command) on itself".
func NewSelfSigned(iss did.DID, cmd command.Command, opts ...Option) (*Token, error) {
return New(iss, cmd, iss, nil, opts...)
}
// ExecutionAllowed verifies that the invocation respects the rules and can be executed.
// IMPORTANT: this function does NOT verify that the subject (and audience if set) makes sense in your context.
func (t *Token) ExecutionAllowed(loader delegation.Loader) error {
return t.executionAllowed(loader, t.arguments)
}
// ExecutionAllowedWithArgsHook is the same as ExecutionAllowed, but allows to modify the arguments before verifying them.
// IMPORTANT: this function does NOT verify that the subject (and audience if set) makes sense in your context.
func (t *Token) ExecutionAllowedWithArgsHook(loader delegation.Loader, hook func(args args.ReadOnly) (*args.Args, error)) error {
newArgs, err := hook(t.arguments.ReadOnly())
if err != nil {
@@ -166,7 +182,7 @@ func (t *Token) Arguments() args.ReadOnly {
return t.arguments.ReadOnly()
}
// Proof() returns the ordered list of cid.Cid which reference the
// Proof returns the ordered list of cid.Cid which reference the
// delegation Tokens that authorize this invocation.
// Ordering is from the leaf Delegation (with aud matching the invocation's iss)
// to the root delegation.
@@ -189,10 +205,10 @@ func (t *Token) Expiration() *time.Time {
return t.expiration
}
// InvokedAt returns the time.Time at which the invocation token was
// IssuedAt returns the time.Time at which the invocation token was
// created.
func (t *Token) InvokedAt() *time.Time {
return t.invokedAt
func (t *Token) IssuedAt() *time.Time {
return t.issuedAt
}
// Cause returns the Token's (optional) cause field which may specify
@@ -201,13 +217,18 @@ func (t *Token) Cause() *cid.Cid {
return t.cause
}
// IsSelfSigned returns true if the token is self-signed, ie it has the same issuer and subject.
func (t *Token) IsSelfSigned() bool {
return t.issuer.Equal(t.subject)
}
// IsValidNow verifies that the token can be used at the current time, based on expiration or "not before" fields.
// This does NOT do any other kind of verifications.
func (t *Token) IsValidNow() bool {
return t.IsValidAt(time.Now())
}
// IsValidNow verifies that the token can be used at the given time, based on expiration or "not before" fields.
// IsValidAt verifies that the token can be used at the given time, based on expiration or "not before" fields.
// This does NOT do any other kind of verifications.
func (t *Token) IsValidAt(ti time.Time) bool {
if t.expiration != nil && ti.After(*t.expiration) {
@@ -228,7 +249,7 @@ func (t *Token) String() string {
res.WriteString(fmt.Sprintf("Nonce: %s\n", base64.StdEncoding.EncodeToString(t.Nonce())))
res.WriteString(fmt.Sprintf("Meta: %s\n", t.Meta()))
res.WriteString(fmt.Sprintf("Expiration: %v\n", t.Expiration()))
res.WriteString(fmt.Sprintf("Invoked At: %v\n", t.InvokedAt()))
res.WriteString(fmt.Sprintf("Issued At: %v\n", t.IssuedAt()))
res.WriteString(fmt.Sprintf("Cause: %v", t.Cause()))
return res.String()
@@ -238,7 +259,7 @@ func (t *Token) validate() error {
var errs error
requiredDID := func(id did.DID, fieldname string) {
if !id.Defined() {
if id == nil {
errs = errors.Join(errs, fmt.Errorf(`a valid did is required for %s: %s`, fieldname, id.String()))
}
}
@@ -273,7 +294,7 @@ func tokenFromModel(m tokenPayloadModel) (*Token, error) {
)
if tkn.issuer, err = did.Parse(m.Iss); err != nil {
return nil, fmt.Errorf("parse iss: %w", err)
return nil, fmt.Errorf("parse issuer: %w", err)
}
if tkn.subject, err = did.Parse(m.Sub); err != nil {
@@ -310,9 +331,9 @@ func tokenFromModel(m tokenPayloadModel) (*Token, error) {
return nil, fmt.Errorf("parse expiration: %w", err)
}
tkn.invokedAt, err = parse.OptionalTimestamp(m.Iat)
tkn.issuedAt, err = parse.OptionalTimestamp(m.Iat)
if err != nil {
return nil, fmt.Errorf("parse invokedAt: %w", err)
return nil, fmt.Errorf("parse IssuedAt: %w", err)
}
tkn.cause = m.Cause

View File

@@ -1,12 +1,14 @@
package invocation_test
import (
_ "embed"
"testing"
"time"
"github.com/MetaMask/go-did-it/didtest"
"github.com/ipfs/go-cid"
"github.com/stretchr/testify/require"
"github.com/ucan-wg/go-ucan/did/didtest"
"github.com/ucan-wg/go-ucan/pkg/args"
"github.com/ucan-wg/go-ucan/pkg/command"
"github.com/ucan-wg/go-ucan/pkg/policy/policytest"
@@ -14,146 +16,260 @@ import (
"github.com/ucan-wg/go-ucan/token/invocation"
)
const (
missingPrivKeyCfg = "CAESQMjRvrEIjpPYRQKmkAGw/pV0XgE958rYa4vlnKJjl1zz/sdnGnyV1xKLJk8D39edyjhHWyqcpgFnozQK62SG16k="
missingTknCIDStr = "bafyreigwypmw6eul6vadi6g6lnfbsfo2zck7gfzsbjoroqs3djhnzzc7mm"
missingDIDStr = "did:key:z6MkwboxFsH3kEuehBZ5fLkRmxi68yv1u38swA4r9Jm2VRma"
)
//go:embed testdata/new.dagjson
var newDagJson []byte
//go:embed testdata/selfsigned.dagjson
var selfsignedDagJson []byte
const missingTknCIDStr = "bafyreigwypmw6eul6vadi6g6lnfbsfo2zck7gfzsbjoroqs3djhnzzc7mm"
var emptyArguments = args.New()
func TestToken_ExecutionAllowed(t *testing.T) {
t.Parallel()
for _, tc := range []struct {
name string
issuer didtest.Persona
cmd command.Command
args *args.Args
proofs []cid.Cid
opts []invocation.Option
err error
}{
// Passes
{
name: "passes - only root",
issuer: didtest.PersonaBob,
cmd: delegationtest.NominalCommand,
args: emptyArguments,
proofs: delegationtest.ProofAliceBob,
err: nil,
},
{
name: "passes - valid chain",
issuer: didtest.PersonaFrank,
cmd: delegationtest.NominalCommand,
args: emptyArguments,
proofs: delegationtest.ProofAliceBobCarolDanErinFrank,
err: nil,
},
{
name: "passes - proof chain attenuates command",
issuer: didtest.PersonaFrank,
cmd: delegationtest.AttenuatedCommand,
args: emptyArguments,
proofs: delegationtest.ProofAliceBobCarolDanErinFrank_ValidAttenuatedCommand,
err: nil,
},
{
name: "passes - invocation attenuates command",
issuer: didtest.PersonaFrank,
cmd: delegationtest.AttenuatedCommand,
args: emptyArguments,
proofs: delegationtest.ProofAliceBobCarolDanErinFrank,
err: nil,
},
{
name: "passes - arguments satisfy empty policy",
issuer: didtest.PersonaFrank,
cmd: delegationtest.NominalCommand,
args: policytest.SpecValidArguments,
proofs: delegationtest.ProofAliceBobCarolDanErinFrank,
err: nil,
},
{
name: "passes - arguments satisfy example policy",
issuer: didtest.PersonaFrank,
cmd: delegationtest.NominalCommand,
args: policytest.SpecValidArguments,
proofs: delegationtest.ProofAliceBobCarolDanErinFrank_ValidExamplePolicy,
err: nil,
},
{
name: "passes - self-signed invocation doesn't require proof",
issuer: didtest.PersonaAlice,
cmd: delegationtest.NominalCommand,
args: emptyArguments,
proofs: nil,
err: nil,
},
{
name: "passes - self-signed invocation accepts a delegation to itself",
issuer: didtest.PersonaAlice,
cmd: delegationtest.NominalCommand,
args: emptyArguments,
proofs: []cid.Cid{delegationtest.TokenAliceAliceCID},
err: nil,
},
t.Run("passes - only root", func(t *testing.T) {
t.Parallel()
// Fails
{
name: "fails - no proof",
issuer: didtest.PersonaCarol,
cmd: delegationtest.NominalCommand,
args: emptyArguments,
proofs: delegationtest.ProofEmpty,
err: invocation.ErrNoProof,
},
{
name: "fails - missing referenced delegation",
issuer: didtest.PersonaCarol,
cmd: delegationtest.NominalCommand,
args: emptyArguments,
proofs: []cid.Cid{cid.MustParse(missingTknCIDStr), delegationtest.TokenAliceBobCID},
err: invocation.ErrMissingDelegation,
},
{
name: "fails - referenced delegation expired",
issuer: didtest.PersonaFrank,
cmd: delegationtest.NominalCommand,
args: emptyArguments,
proofs: delegationtest.ProofAliceBobCarolDanErinFrank_InvalidExpired,
err: invocation.ErrTokenInvalidNow,
},
{
name: "fails - referenced delegation inactive",
issuer: didtest.PersonaFrank,
cmd: delegationtest.NominalCommand,
args: emptyArguments,
proofs: delegationtest.ProofAliceBobCarolDanErinFrank_InvalidInactive,
err: invocation.ErrTokenInvalidNow,
},
{
name: "fails - last (or only) delegation not root",
issuer: didtest.PersonaFrank,
cmd: delegationtest.NominalCommand,
args: emptyArguments,
proofs: []cid.Cid{delegationtest.TokenErinFrankCID, delegationtest.TokenDanErinCID, delegationtest.TokenCarolDanCID},
err: invocation.ErrLastNotRoot,
},
{
name: "fails - broken chain",
issuer: didtest.PersonaFrank,
cmd: delegationtest.NominalCommand,
args: emptyArguments,
proofs: []cid.Cid{delegationtest.TokenCarolDanCID, delegationtest.TokenAliceBobCID},
err: invocation.ErrBrokenChain,
},
{
name: "fails - first not issued to invoker",
issuer: didtest.PersonaFrank,
cmd: delegationtest.NominalCommand,
args: emptyArguments,
proofs: []cid.Cid{delegationtest.TokenBobCarolCID, delegationtest.TokenAliceBobCID},
err: invocation.ErrBrokenChain,
},
{
name: "fails - proof chain expands command",
issuer: didtest.PersonaFrank,
cmd: delegationtest.NominalCommand,
args: emptyArguments,
proofs: delegationtest.ProofAliceBobCarolDanErinFrank_InvalidExpandedCommand,
err: invocation.ErrCommandNotCovered,
},
{
name: "fails - invocation expands command",
issuer: didtest.PersonaFrank,
cmd: delegationtest.ExpandedCommand,
args: emptyArguments,
proofs: delegationtest.ProofAliceBobCarolDanErinFrank,
err: invocation.ErrCommandNotCovered,
},
{
name: "fails - inconsistent subject",
issuer: didtest.PersonaFrank,
cmd: delegationtest.ExpandedCommand,
args: emptyArguments,
proofs: delegationtest.ProofAliceBobCarolDanErinFrank_InvalidSubject,
err: invocation.ErrWrongSub,
},
{
name: "fails - arguments don't satisfy example policy",
issuer: didtest.PersonaFrank,
cmd: delegationtest.NominalCommand,
args: policytest.SpecInvalidArguments,
proofs: delegationtest.ProofAliceBobCarolDanErinFrank_ValidExamplePolicy,
err: invocation.ErrPolicyNotSatisfied,
},
{
name: "fails - self-signed invocation refuses a delegation to itself for a different DID",
issuer: didtest.PersonaAlice,
cmd: delegationtest.NominalCommand,
args: emptyArguments,
proofs: []cid.Cid{delegationtest.TokenBobBobCID},
err: invocation.ErrWrongSub,
},
} {
t.Run(tc.name, func(t *testing.T) {
tc.opts = append(tc.opts, invocation.WithArguments(tc.args))
testPasses(t, didtest.PersonaBob, delegationtest.NominalCommand, emptyArguments, delegationtest.ProofAliceBob)
})
t.Run("passes - valid chain", func(t *testing.T) {
t.Parallel()
testPasses(t, didtest.PersonaFrank, delegationtest.NominalCommand, emptyArguments, delegationtest.ProofAliceBobCarolDanErinFrank)
})
t.Run("passes - proof chain attenuates command", func(t *testing.T) {
t.Parallel()
testPasses(t, didtest.PersonaFrank, delegationtest.AttenuatedCommand, emptyArguments, delegationtest.ProofAliceBobCarolDanErinFrank_ValidAttenuatedCommand)
})
t.Run("passes - invocation attenuates command", func(t *testing.T) {
t.Parallel()
testPasses(t, didtest.PersonaFrank, delegationtest.AttenuatedCommand, emptyArguments, delegationtest.ProofAliceBobCarolDanErinFrank)
})
t.Run("passes - arguments satisfy empty policy", func(t *testing.T) {
t.Parallel()
testPasses(t, didtest.PersonaFrank, delegationtest.NominalCommand, policytest.SpecValidArguments, delegationtest.ProofAliceBobCarolDanErinFrank)
})
t.Run("passes - arguments satify example policy", func(t *testing.T) {
t.Parallel()
testPasses(t, didtest.PersonaFrank, delegationtest.NominalCommand, policytest.SpecValidArguments, delegationtest.ProofAliceBobCarolDanErinFrank_ValidExamplePolicy)
})
t.Run("fails - no proof", func(t *testing.T) {
t.Parallel()
testFails(t, invocation.ErrNoProof, didtest.PersonaCarol, delegationtest.NominalCommand, emptyArguments, delegationtest.ProofEmpty)
})
t.Run("fails - missing referenced delegation", func(t *testing.T) {
t.Parallel()
missingTknCID, err := cid.Parse(missingTknCIDStr)
tkn, err := invocation.New(tc.issuer.DID(), tc.cmd, didtest.PersonaAlice.DID(), tc.proofs, tc.opts...)
require.NoError(t, err)
prf := []cid.Cid{missingTknCID, delegationtest.TokenAliceBobCID}
testFails(t, invocation.ErrMissingDelegation, didtest.PersonaCarol, delegationtest.NominalCommand, emptyArguments, prf)
})
t.Log(tkn.String())
t.Run("fails - referenced delegation expired", func(t *testing.T) {
t.Parallel()
err = tkn.ExecutionAllowed(delegationtest.GetDelegationLoader())
testFails(t, invocation.ErrTokenInvalidNow, didtest.PersonaFrank, delegationtest.NominalCommand, emptyArguments, delegationtest.ProofAliceBobCarolDanErinFrank_InvalidExpired)
})
t.Run("fails - referenced delegation inactive", func(t *testing.T) {
t.Parallel()
testFails(t, invocation.ErrTokenInvalidNow, didtest.PersonaFrank, delegationtest.NominalCommand, emptyArguments, delegationtest.ProofAliceBobCarolDanErinFrank_InvalidInactive)
})
t.Run("fails - last (or only) delegation not root", func(t *testing.T) {
t.Parallel()
prf := []cid.Cid{delegationtest.TokenErinFrankCID, delegationtest.TokenDanErinCID, delegationtest.TokenCarolDanCID}
testFails(t, invocation.ErrLastNotRoot, didtest.PersonaFrank, delegationtest.NominalCommand, emptyArguments, prf)
})
t.Run("fails - broken chain", func(t *testing.T) {
t.Parallel()
prf := []cid.Cid{delegationtest.TokenCarolDanCID, delegationtest.TokenAliceBobCID}
testFails(t, invocation.ErrBrokenChain, didtest.PersonaFrank, delegationtest.NominalCommand, emptyArguments, prf)
})
t.Run("fails - first not issued to invoker", func(t *testing.T) {
t.Parallel()
prf := []cid.Cid{delegationtest.TokenBobCarolCID, delegationtest.TokenAliceBobCID}
testFails(t, invocation.ErrBrokenChain, didtest.PersonaFrank, delegationtest.NominalCommand, emptyArguments, prf)
})
t.Run("fails - proof chain expands command", func(t *testing.T) {
t.Parallel()
testFails(t, invocation.ErrCommandNotCovered, didtest.PersonaFrank, delegationtest.NominalCommand, emptyArguments, delegationtest.ProofAliceBobCarolDanErinFrank_InvalidExpandedCommand)
})
t.Run("fails - invocation expands command", func(t *testing.T) {
t.Parallel()
testFails(t, invocation.ErrCommandNotCovered, didtest.PersonaFrank, delegationtest.ExpandedCommand, emptyArguments, delegationtest.ProofAliceBobCarolDanErinFrank)
})
t.Run("fails - inconsistent subject", func(t *testing.T) {
t.Parallel()
testFails(t, invocation.ErrWrongSub, didtest.PersonaFrank, delegationtest.ExpandedCommand, emptyArguments, delegationtest.ProofAliceBobCarolDanErinFrank_InvalidSubject)
})
t.Run("passes - arguments satisfy example policy", func(t *testing.T) {
t.Parallel()
testFails(t, invocation.ErrPolicyNotSatisfied, didtest.PersonaFrank, delegationtest.NominalCommand, policytest.SpecInvalidArguments, delegationtest.ProofAliceBobCarolDanErinFrank_ValidExamplePolicy)
})
}
func test(t *testing.T, persona didtest.Persona, cmd command.Command, args *args.Args, prf []cid.Cid, opts ...invocation.Option) error {
t.Helper()
opts = append(opts, invocation.WithArguments(args))
tkn, err := invocation.New(persona.DID(), cmd, didtest.PersonaAlice.DID(), prf, opts...)
require.NoError(t, err)
return tkn.ExecutionAllowed(delegationtest.GetDelegationLoader())
}
func testFails(t *testing.T, expErr error, persona didtest.Persona, cmd command.Command, args *args.Args, prf []cid.Cid, opts ...invocation.Option) {
err := test(t, persona, cmd, args, prf, opts...)
require.ErrorIs(t, err, expErr)
}
func testPasses(t *testing.T, persona didtest.Persona, cmd command.Command, args *args.Args, prf []cid.Cid, opts ...invocation.Option) {
err := test(t, persona, cmd, args, prf, opts...)
if tc.err != nil {
require.ErrorIs(t, err, tc.err)
} else {
require.NoError(t, err)
}
})
}
}
const (
nonce = "6roDhGi0kiNriQAz7J3d+bOeoI/tj8ENikmQNbtjnD0"
subjectCmd = "/foo/bar"
)
func TestConstructors(t *testing.T) {
cmd, err := command.Parse(subjectCmd)
require.NoError(t, err)
iat, err := time.Parse(time.RFC3339, "2100-01-01T00:00:00Z")
require.NoError(t, err)
exp, err := time.Parse(time.RFC3339, "2200-01-01T00:00:00Z")
require.NoError(t, err)
t.Run("New", func(t *testing.T) {
tkn, err := invocation.New(
didtest.PersonaAlice.DID(), cmd, didtest.PersonaBob.DID(),
delegationtest.ProofAliceBob,
invocation.WithNonce([]byte(nonce)),
invocation.WithIssuedAt(iat),
invocation.WithExpiration(exp),
invocation.WithArgument("foo", "bar"),
invocation.WithMeta("baz", 123),
)
require.NoError(t, err)
require.False(t, tkn.IsSelfSigned())
data, err := tkn.ToDagJson(didtest.PersonaAlice.PrivKey())
require.NoError(t, err)
require.JSONEq(t, string(newDagJson), string(data))
})
t.Run("Self-Signed", func(t *testing.T) {
tkn, err := invocation.NewSelfSigned(
didtest.PersonaAlice.DID(), cmd,
invocation.WithNonce([]byte(nonce)),
invocation.WithIssuedAt(iat),
invocation.WithExpiration(exp),
invocation.WithArgument("foo", "bar"),
invocation.WithMeta("baz", 123),
)
require.NoError(t, err)
require.True(t, tkn.IsSelfSigned())
data, err := tkn.ToDagJson(didtest.PersonaAlice.PrivKey())
require.NoError(t, err)
require.JSONEq(t, string(selfsignedDagJson), string(data))
})
}

Some files were not shown because too many files have changed in this diff Show More