This specification describes a portable, extensible, JSON-LD wallet, supporting digital currencies and credentials.
This document is experimental and is undergoing heavy development. It is inadvisable to implement the specification in its current form. An experimental implementation is available.
Traditional physical wallets are used to store a variety of personal assets such as cash, credit cards, driver license, health insurance, and business cards. Today we also have a wide variety of digital wallets to store and access digital versions of these same assets, with more options coming into the market every day. However, each wallet represents data and capabilities differently, sometimes intentionally to facilitate vendor lock in.
Imagine you had to carry a dozen different wallets with you at all times, and to use each one independently based on the situation. The wallets are disconnected, and the burden is on either the holder or the verifier to request all required information for each transaction. The result is a cumbersome user experience (not dissimilar to account and password management today) and expensive business implementation to support different wallets. What is missing is a standardized structure - a universal wallet - that can effectively point to and comprehend each digital asset in its current location. This universal wallet not only offers a convenient access point for people and machines to organize their assets (akin to a traditional physical wallet), but it also enables awareness and relationships between those assets as needed for real-world use.
The purpose of this specification is to design an abstract data model and set of interfaces that approximate a physical wallet system and its common uses.
There are many existing software systems which manage subsets or supersets of the information represented in digital wallets. This specification aims to be compatible with those systems, by allowing them to continue to manage the information and inferfaces, so long as they can be adequately described at both a data model, and interface level.
The property of representing data and interfaces as they exist, where they exist today, is a critical component of this specification. We fully expect this specification to live or die by its ability to achieve this property.
The following terms are used to describe concepts involved in the universal wallet.
Each entity is represented as a JSON Object, with relationships between entities described using identifiers.
A profile is a named bucket for grouping wallet content.
A profile MAY be used to group all correlatable wallet items together.
A profile MAY be used to manage separate external personal, or organizational identities and their associated data.
Here is an example of a personal profile.
{ "@context": ["https://w3id.org/wallet/v1"], "id": "did:example:123456789abcdefghi", "type": "Person", "name": "John Smith", "image": "https://via.placeholder.com/150", "description" : "Professional software developer for Acme Corp.", "tags": ["professional", "person"], "correlation": ["4058a72a-9523-11ea-bb37-0242ac130002"] }
Here is an example of an organization profile.
{ "@context": ["https://w3id.org/wallet/v1"], "id": "did:example:123456789abcdefghi", "type": "Organization", "name": "Acme Corp.", "image": "https://via.placeholder.com/150", "description" : "A software company.", "tags": ["professional", "organization"], "correlation": ["4058a72a-9523-11ea-bb37-0242ac130002"] }
A cached result of DID Resolution. Useful when device connectivity is intermitent, or offline support is required.
Here is an example of a cached did document.
{ "@context": [ "https://w3id.org/wallet/v1" ], "id": "did:example:123", "type": ["CachedDIDDocument"], "name": "Farming Sensor DID Document", "image": "https://via.placeholder.com/150", "description": "An IoT device in the middle of a corn field.", "tags": ["professional"], "correlation": ["4058a72a-9523-11ea-bb37-0242ac130002"], "created": "2017-06-18T21:19:10Z", "expires": "2026-06-18T21:19:10Z", "didDocument": { "@context": "https://w3id.org/did/v0.11", "id": "did:example:123", "assertionMethod": [ "did:example:123#z6MksHh7qHWvybLg5QTPPdG2DgEjjduBDArV9EF9mRiRzMBN" ], "authentication": [ "did:example:123#z6MksHh7qHWvybLg5QTPPdG2DgEjjduBDArV9EF9mRiRzMBN" ], "capabilityDelegation": [ "did:example:123#z6MksHh7qHWvybLg5QTPPdG2DgEjjduBDArV9EF9mRiRzMBN" ], "capabilityInvocation": [ "did:example:123#z6MksHh7qHWvybLg5QTPPdG2DgEjjduBDArV9EF9mRiRzMBN" ], "keyAgreement": [ { "id": "did:example:123#zC5iai1sL93gQxn8LKh1i42fTbpfar65dVx4NYznYfG3Y5", "type": "X25519KeyAgreementKey2019", "controller": "did:example:123", "publicKeyBase58": "6DrzegWwfw8Xg5MsHX95sVnJaPmtXP214B5X9hkG9oRs" } ], "publicKey": [ { "id": "did:example:123#z6MksHh7qHWvybLg5QTPPdG2DgEjjduBDArV9EF9mRiRzMBN", "type": "Ed25519VerificationKey2018", "controller": "did:example:123", "publicKeyBase58": "DqS5F3GVe3rCxucgi4JBNagjv4dKoHc8TDLDw9kR58Pz" } ] } }
An amount of currency controlled by one or more Keys.
Here is an example of some bitcoin stored on a testnet.
{ "@context": ["https://w3id.org/wallet/v1"], "id": "https://live.blockcypher.com/btc-testnet/address/mu6vftfsBxJDhnUQVrZfwjzj5BL5WRvLUH/", "type": "Currency", "name": "BTC for Testing", "image": "https://via.placeholder.com/150", "description" : "Bitcoin reserved for testing", "tags": ["personal"], "amount": "7.00749119", "currency": "BTC", "controller": ["did:example:123"], "correlation": ["4058a72a-9523-11ea-bb37-0242ac130002"] }
Here is an example of some ethereum stored on a testnet.
{ "@context": ["https://w3id.org/wallet/v1"], "id": "https://ropsten.etherscan.io/address/0x74fd35392f1c2a97c6080e0394b1995b0e63c8bf", "type": "Currency", "name": "ETH for Tips", "image": "https://via.placeholder.com/150", "description" : "Ethereum reserved for tipping software developers.", "tags": ["personal"], "amount": "8.142406194939252896", "currency": "ETH", "controller": ["did:ethr:0x74fd35392f1c2a97c6080e0394b1995b0e63c8bf#key-0"], "correlation": ["4058a72a-9523-11ea-bb37-0242ac130002"] }
Here is an example of some ethereum stored on a testnet requiring multisig.
{ "id": "https://ropsten.etherscan.io/address/0x658e4fe24b34589492b18b1a45294be0601606a9", "type": "Currency", "name": "ETH for Games", "image": "https://via.placeholder.com/150", "description" : "Ethereum reserved for games.", "tags": ["personal"], "amount": "6,271.91386730845876097", "currency": "ETH", "controller": ["did:ethr:0x658e4fe24b34589492b18b1a45294be0601606a9#key-0", "did:ethr:0x658e4fe24b34589492b18b1a45294be0601606a9#key-1"], "quorum": 2, "correlation": ["4058a72a-9523-11ea-bb37-0242ac130002"] }
A set of claims about a subject.
MAY be presented with one or more Keys.
Here is an example of a University Degree represented using the [[vc-data-model]].
{ "@context": [ "https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1" ], "id": "http://example.gov/credentials/3732", "type": [ "VerifiableCredential", "UniversityDegreeCredential" ], "issuer": { "id": "did:example:123456789abcdefghi" }, "issuanceDate": "2020-03-10T04:24:12.164Z", "credentialSubject": { "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", "degree": { "type": "BachelorDegree", "name": "Bachelor of Science and Arts" } }, "proof": { "type": "JsonWebSignature2020", "created": "2020-03-21T17:51:48Z", "verificationMethod": "did:example:123456789abcdefghi#_Qq0UL2Fq651Q0Fjd6TvnYE-faHiOpRlPVQcY_-tA4A", "proofPurpose": "assertionMethod", "jws": "eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFZERTQSJ9..OPxskX37SK0FhmYygDk-S4csY_gNhCUgSOAaXFXDTZx86CmI5nU9xkqtLWg-f4cqkigKDdMVdtIqWAvaYx2JBA" } }
Here is an example of an JWT Credential.
{ "protected": { "kid": "did:web:identity.foundation#_Qq0UL2Fq651Q0Fjd6TvnYE-faHiOpRlPVQcY_-tA4A", "alg": "EdDSA" }, "payload": { "sub": "did:web:identity.foundation", "iss": "did:web:identity.foundation", "nbf": 1586814292, "exp": 1589406292, "vc": { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://identity.foundation/.well-known/contexts/did-configuration-v0.0.jsonld" ], "issuer": "did:web:identity.foundation", "issuanceDate": "2020-04-13T16:44:52-05:00", "expirationDate": "2020-05-13T16:44:52-05:00", "type": [ "VerifiableCredential", "DomainLinkageCredential" ], "credentialSubject": { "id": "did:web:identity.foundation", "domain": "identity.foundation" } } }, "signature": "qEV-lat1Wc8qKU_OLbTd07fx7tkW12QhkyiB912OsHi4FmkTWr_qMAFyW8IZxaQAsXg1E4yCRe8VsfGYaePfCg" }
Here is an example of an Indy Credential.
Proposing to wrap Hyperledger Indy Credentials with useful meta data, and provide a JSON-LD context for them.
{ "@context": [ "https://www.w3.org/2018/credentials/v1", "https://example.com/hyperledger/indy/v1" ], "id": "urn:uui:5e2a2cfc-ddee-4b6e-b1df-b25d5c381dd6", "type": ["HyperledgerIndyCredentialRequest"], "name": "Request for ZKP of PII", "image": "https://via.placeholder.com/150", "description": "Some hyperledger indy request", "tags": ["personal"], "controller": ["did:example:123"], "correlation": ["4058a72a-9523-11ea-bb37-0242ac130002"], "request": { "blinded_ms": { "committed_attributes": {}, "hidden_attributes": ["master_secret"], "u": "65831452313882581230262709313640398502180121409437456701285942297697220273020651832867867646867694104285264882901784486060003798041322783654882887801338491262118680258721202637330550769869214264954742835710055875494951347903964659726990419477041411071293939395959337387632115898651722739118077413287212136124581126858655228247591827039715635869509104285523508350517189259095099031335038010813127434575838122472539671883003577935935805849721520698913035313700463716817299972399222663463531626690265819737278764702201558856023597942255295546958215228209847949123140888705477748125028989834201043317313234794999670960309", "ur": null }, "blinded_ms_correctness_proof": { "c": "109860678073076085235251415455172114757447490048716300713084480862613855161594", "m_caps": { "master_secret": "26283368873168710647823575287384506775329371134097934071944480688608740447086822076157945371978097759120680279871932367038315961209475528490588458124513336494442045082962002632630" }, "r_caps": {}, "v_dash_cap": "2280251997303109215440229941746203124645437910879700880787994443943315426654016847375797993806524993944624797926394628097776282593677641139413080324847861793144967254410329241135241448735975536630491881499127637586742389241597839730305081627234920106253837671010874865272721731993787096927927219667907076510252353984721949818101724187470187212834753509683017877231098388634684162763868165666439930098806964029632419913797905735247261174021083829716744013146112407108188748399721262104236090674581750516219214189074147796588753301588559493169281419642497122075637138527711629397854490786655717000499533957790924731039896458915259618414177079172716906654070782024546965289973737179244936586584621455129955294625933138084" }, "cred_def_id": "97RDzn8aDviHUQQKPXg96e:3:CL:1:cred_def_tag", "nonce": "787732518675896939298806", "prover_did": "VsKV7grR1BUE29mG2Fm2kX" } }
Here is an example of an Indy Credential Response.
{ "@context": [ "https://www.w3.org/2018/credentials/v1", "https://example.com/hyperledger/indy/v1" ], "id": "urn:uui:5e2a2cfc-ddee-4b6e-b1df-b25d5c381dd6", "type": ["HyperledgerIndyCredentialResponse"], "name": "Response with ZKP of PII", "image": "https://via.placeholder.com/150", "description": "Some hyperledger indy response", "tags": ["personal"], "controller": ["did:example:123"], "correlation": ["4058a72a-9523-11ea-bb37-0242ac130002"], "response": { "cred_def_id": "97RDzn8aDviHUQQKPXg96e:3:CL:1:cred_def_tag", "rev_reg": null, "rev_reg_id": null, "schema_id": "1", "signature": { "p_credential": { "a": "95353830375173330011563360059148264672898064240769511250683274343595259814385881580652435846242305610602775955153225949828351822615582300818164568659759210654812158114909671116500854641792747538502940562299939329775539393907208674840307912497761924491759626001631051978385141797844740405389371307810867892266393402889311183432317570029074621797181653694420095514029762818719468632709966063515795023890061161695773247748450608404761004379958193940141773792823139355492617241722063652768459827450028875759363009052805727635793672494079344330863114982873831106116041797167251966936936806424711883143669500689657231135606", "e": "259344723055062059907025491480697571938277889515152306249728583105665800713306759149981690559193987143012367913206299323899696942213235956742930148508371517214363847909185411372253", "m_2": "87933324484247736755432182254530234578539725681347360397600269871642228431291", "v": "9980048782698213650029707306155459223351306678221752614666406496131317042580709639463968555501635926971838913872812808348795802668959822338264694189410327519660902443001438239011481179716268316444260971946516885083303128874909099593395255544689704182390571217148562533306555613083811625224310294070840596291508202160863034924955239229626686346699964038203572055526536874808785883442434204203578065957249420787817929622802282705534703609382585731044976967091334711355681718119910796427448184020435027328010716618250816760780193851507746646202423419420085349209268468391222040632949331381277174716781756370851681892517534221307517998851557466372447869765146986972380453630642444945932431258454568836958535197445982382692900624253982717831288480544351529597240580788825685640983253528750762130639934973110889811748482529784" }, "r_credential": null }, "signature_correctness_proof": { "c": "111039946245998422293228198882690698427961176580797991507430891006675146356597", "se": "22605964272161668401729392750124222261476956426739374858535661640179592757898860024832882984205300374191737843804934686452004477429402832292629718216663316164939570354876583921389754652453753209439712424429741656877542117083074742649581822964695267610947419213636358675100501109665802628234428907141311421109128613552987278370127477282566942966334173257609909151324991747736857761765991353008203982871999513346493415736923977797669183887730008747615226061509085005490533206472742385316192550536165419027378783950304188984918698568811667562161240994301427542320560168961460242425150722543163690905028839780636297387853" }, "values": { "age": { "encoded": "28", "raw": "28" }, "height": { "encoded": "175", "raw": "175" }, "name": { "encoded": "1139481716457488690172217916278103335", "raw": "Alex" }, "sex": { "encoded": "5944657099558967239210949258394887428692050081607692519917050011144233115103", "raw": "male" } }, "witness": null } }
A cryptographic key. Used for signing, encrypting or hashing.
Here is an example of storing an Ed25519 key using JWK.
{ "@context": ["https://w3id.org/wallet/v1"], "id": "urn:uuid:53d846c8-9525-11ea-bb37-0242ac130002", "name": "My Test Key 1", "image": "https://via.placeholder.com/150", "description" : "For testing only, totally compromised.", "tags": ["professional", "organization", "compromised"], "correlation": ["4058a72a-9523-11ea-bb37-0242ac130002"], "controller": ["did:example:123#_Qq0UL2Fq651Q0Fjd6TvnYE-faHiOpRlPVQcY_-tA4A"], "type": "Ed25519VerificationKey2018", "publicKeyJwk": { "crv": "Ed25519", "x": "VCpo2LMLhn6iWku8MKvSLg2ZAoC-nlOyPVQaO3FxVeQ", "kty": "OKP", "kid": "_Qq0UL2Fq651Q0Fjd6TvnYE-faHiOpRlPVQcY_-tA4A" }, "privateKeyJwk": { "crv": "Ed25519", "x": "VCpo2LMLhn6iWku8MKvSLg2ZAoC-nlOyPVQaO3FxVeQ", "d": "tP7VWE16yMQWUO2G250yvoevfbfxY25GjHglTP3ZOyU", "kty": "OKP", "kid": "_Qq0UL2Fq651Q0Fjd6TvnYE-faHiOpRlPVQcY_-tA4A" } }
Here is an example of storing an Ed25519 key using base58.
{ "@context": ["https://w3id.org/wallet/v1"], "id": "urn:uuid:e8fc7810-9524-11ea-bb37-0242ac130002", "name": "My Test Key 2", "image": "https://via.placeholder.com/150", "description" : "For testing only, totally compromised.", "tags": ["professional", "organization", "compromised"], "correlation": ["4058a72a-9523-11ea-bb37-0242ac130002"], "controller": ["did:key:z6MkjjCpsoQrwnEmqHzLdxWowXk5gjbwor4urC1RPDmGeV8r#z6MkjjCpsoQrwnEmqHzLdxWowXk5gjbwor4urC1RPDmGeV8r"], "type": "Ed25519VerificationKey2018", "privateKeyBase58": "3CQCBKF3Mf1tU5q1FLpHpbxYrNYxLiZk4adDtfyPEfc39Wk6gsTb2qoc1ZtpqzJYdM1rG4gpaD3ZVKdkiDrkLF1p", "publicKeyBase58": "6GwnHZARcEkJio9dxPYy6SC5sAL6PxpZAB6VYwoFjGMU" }
Here is an example of a key which is stored in a remote kms.
{ "@context": ["https://w3id.org/wallet/v1"], "id": "urn:uuid:e8fc7810-9524-11ea-bb37-0242ac130006", "name": "My Test Key 3", "image": "https://via.placeholder.com/150", "description" : "For testing only, totally compromised.", "tags": ["professional", "organization", "compromised"], "correlation": ["4058a72a-9523-11ea-bb37-0242ac130002"], "controller": ["did:key:z6MkjjCpsoQrwnEmqHzLdxWowXk5gjbwor4urC1RPDmGeV8r#z6MkjjCpsoQrwnEmqHzLdxWowXk5gjbwor4urC1RPDmGeV8r"], "type": "Ed25519VerificationKey2018", "publicKeyJwk": { "crv": "Ed25519", "x": "VCpo2LMLhn6iWku8MKvSLg2ZAoC-nlOyPVQaO3FxVeQ", "kty": "OKP", "kid": "_Qq0UL2Fq651Q0Fjd6TvnYE-faHiOpRlPVQcY_-tA4A" }, "privateKeyWebKms": "http://example.com/kms/keystores/0/keys/0" }
Here is an example of a local, hardware isolated key.
{ "@context": ["https://w3id.org/wallet/v1"], "id": "urn:uuid:e8fc7810-9524-11ea-bb37-0242ac130006", "name": "My Test Key 3", "image": "https://via.placeholder.com/150", "description" : "For testing only, totally compromised.", "tags": ["professional", "organization", "compromised"], "correlation": ["4058a72a-9523-11ea-bb37-0242ac130002"], "controller": ["did:key:z6MkjjCpsoQrwnEmqHzLdxWowXk5gjbwor4urC1RPDmGeV8r#z6MkjjCpsoQrwnEmqHzLdxWowXk5gjbwor4urC1RPDmGeV8r"], "type": "Ed25519VerificationKey2018", "publicKeyJwk": { "crv": "Ed25519", "x": "VCpo2LMLhn6iWku8MKvSLg2ZAoC-nlOyPVQaO3FxVeQ", "kty": "OKP", "kid": "_Qq0UL2Fq651Q0Fjd6TvnYE-faHiOpRlPVQcY_-tA4A" }, "privateKeySecureEnclave": "urn:ios:enclave:uuid:e8fc7810-9524-11ea-bb37-0242ac130789" }
An identifier, frequently derived from a key. Used for verifying signatures or sending currency.
Here is an example of storing an EthereumAddress.
{ "@context": [ "https://w3id.org/wallet/v1" ], "id": "did:ethr:0x774477c4cd54718d32d4df393415796b9bfcb63c", "type": "EthereumAddress", "controller": [ "did:ethr:0x774477c4cd54718d32d4df393415796b9bfcb63c" ], "name": "MetaMask Account", "image": "https://metamask.io/images/webclip.png", "description": "My ropsten testnet account.", "privateKeyBrowser": "urn:metamask:0x774477c4cd54718d32d4df393415796b9bfcb63c" }
An ordered list of memorable words.
MAY be used as a source of memorable Entropy.
MAY be used as input to a KDF.
Here is an example of storing a mnemonic as a Secret.
{ "@context": ["https://w3id.org/wallet/v1"], "id": "urn:uuid:c410e44a-9525-11ea-bb37-0242ac130002", "name": "My Ropsten Mnemonic 1", "image": "https://via.placeholder.com/150", "description" : "For testing only, totally compromised.", "tags": ["professional", "organization", "compromised"], "correlation": ["4058a72a-9523-11ea-bb37-0242ac130002"], "type": "Mnemonic", "value": "humble piece toy mimic miss hurdle smile awkward patch drama hurry mixture" }
MAY be used as input to a KDF.
Here is an example of storing entropy as a Secret.
{ "@context": ["https://w3id.org/wallet/v1"], "id": "urn:uuid:c410e44a-9525-11ea-bb37-0242ac130002", "name": "My Test Entropy 1", "image": "https://via.placeholder.com/150", "description" : "For testing only, totally compromised.", "tags": ["professional", "organization", "compromised"], "correlation": ["4058a72a-9523-11ea-bb37-0242ac130002"], "type": "Entropy", "multibase": "z6MkuVZVSKLUNHRjXBXcEwvG5yiNHLhzBeXRjAkwmgSYensE" }
Information about a relationship between identifiers.
{ "@context": ["https://w3id.org/wallet/v1"], "id": "urn:uuid:c410e44a-9525-11ea-bb37-0242ac130006", "name": "My Health Record Certifier", "image": "https://via.placeholder.com/150", "description" : "The identifier that issues health record credentials.", "tags": ["professional"], "correlation": ["4058a72a-9523-11ea-bb37-0242ac130002"], "type": "Connection", "connection": { "created_at": "2020-06-01 14:05:54.150111Z", "their_did": "SkL2sdiv3RrPk3QtjT3Mjs", "routing_state": "none", "invitation_key": "EGsWeE95ANRp9GRNR3fjaWyB1tRqhaBuc69iMg7zBFij", "accept": "auto", "their_label": "Alice.Agent", "my_did": "4zRzv8DtEaZqSreoNb2dpJ", "state": "active", "initiator": "self", "connection_id": "3b6e568d-1cee-4327-915c-0e9d39ef2e88", "invitation_mode": "once", "updated_at": "2020-06-01 14:06:58.610756Z" }, }
Information about wallet data.
Here is an example where meta data is used to remind the wallet controller that a credential has likely be exposed because of a breach notification.
{ "@context": ["https://w3id.org/wallet/v1"], "id": "urn:uuid:2905324a-9524-11ea-bb37-0242ac130002", "type": "MetaData", "name": "Degree Notes", "image": "https://via.placeholder.com/150", "description" : "Personal notes about this degree.", "tags": ["professional", "organization"], "correlation": ["urn:uuid:4058a72a-9523-11ea-bb37-0242ac130002"], "note": "I've shared this degree, with many websites that have been breached. It should be considered public information at this point :(" }
Here is an example where meta data is used to remind the wallet controller that they use a mnemonic for manage their ethereum accounts and funds for testing.
{ "@context": ["https://w3id.org/wallet/v1"], "id": "urn:uuid:2905324a-9524-11ea-bb37-0242ac130002", "type": "MetaData", "name": "Ropsten Testnet HD Accounts", "image": "https://via.placeholder.com/150", "description" : "My Ethereum TestNet Accounts", "tags": ["professional", "organization"], "correlation": ["urn:uuid:4058a72a-9523-11ea-bb37-0242ac130002"], "hdPath": "m’/44’/60’/0’", "target": ["urn:uuid:c410e44a-9525-11ea-bb37-0242ac130002"] }
Also known as a signed encrypted wallet.
An integrity protected, authenticated and privacy preserving representation of a wallet.
{ "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/wallet/v1", ], "id": "http://example.gov/wallet/3732", "type": ["VerifiableCredential", "EncryptedWallet"], "issuer": "did:example:123", "issuanceDate": "2020-05-22T17:38:21.910Z", "credentialSubject": { "id": "did:example:123", "contents": [ { "id": "urn:uuid:e8fc7810-9524-11ea-bb37-0242ac130002", "jwe": { "protected": "eyJlbmMiOiJYQzIwUCJ9", "recipients": [ { "header": { "kid": "did:key:z6MkjMSYauuMgx9azEyUnTW5o5jFRkbBu5T83f39uNwnsGmm#z6LSoGtZSrUMZudAagzEfYf7k8jHZcGD79Sox7v4wCkDKNSw", "alg": "ECDH-ES+A256KW", "epk": { "kty": "OKP", "crv": "X25519", "x": "RfXdxTfIzilWBzWWX3ovHBDzgDcLNy0BFJWSxa0dqnw" }, "apu": "RfXdxTfIzilWBzWWX3ovHBDzgDcLNy0BFJWSxa0dqnw", "apv": "ZGlkOmtleTp6Nk1rak1TWWF1dU1neDlhekV5VW5UVzVvNWpGUmtiQnU1VDgzZjM5dU53bnNHbW0jejZMU29HdFpTclVNWnVkQWFnekVmWWY3azhqSFpjR0Q3OVNveDd2NHdDa0RLTlN3" }, "encrypted_key": "-ABaawsVfTxJKmYVMhC0UWGQRZaYaLr8WdTBlugLOADXxrlOP-5M-A" } ], "iv": "zjJPRrj0TGez9JYkChTrB3iqKoDkiBhn", "ciphertext": "pPqPLiMuJLygwKbsDh-QWw0y5CHmQMINXPc1-qgsKLCFDTJ6ytqoTF35rM5KxSfeVCk74HLtIUIbDvNx53xr2YGqOi9-yDHrT3KurY8CIiBDTYCHkW50wgJq-Ac_gE3lSEEOYT1ZF4izf6GoA1jnI7alxD8ScgOGv2OuWLKEhV5HNEBLUpNz8Di7LDmRLSvAroiWE0rBu-xl7dRrLRH3ZKUzc-R6vrG_X56o-ivjUCfcvrjTnh2pgmVFo27BA34edYbLHIbKcWjMoSBEgmeY30ZuQt_KXK0vDQ6pFmMW5n8oISjPYv8rdicwNPfpCR89x11Vgrde419guqIwEsuOyvCAWidzgFeUu7jeyxjyYcNaIM1r2mq7OXnTODAFBzK4lWqniiDYWy2CLcPTHIXHnhq9YvPOhjqFz6aBbf_XqiFdIQZgOX2oDX6zGHg9fvw4AZc3_N3bCHRbZzKkf-AyvvHxPb9dphU1OdQmnRefYg-xtEQnlwk704J26xZU2qBn7YIJh_nrh9u41KqA0FSlYQsGiyW7SvOf2_LaA9qr17eA7HqY7Lst53_kiYhgWCd7g8hTWiT5G7QVLS_wx89DUpNfz_bxqQU0f17W2L0rLSLCWwaqUjxlLbPlFnpWgokbnxOMOETDvt_8DGUbczRou7Z4NyQ6ZFCOV4TD0AFRCM-RTj-YR6UC_UAAIvEPJep3Uz8elJzkf7xevnWKRSGyFLIUie0tSwZ7hCtjdvP3tOKidwy56jHtOQ_R6wx_9taVc3_5IeoP-4wZ4DNOm_IS9jb6csWmRvyW5GoRx-robqraPCM64SKg9EM", "tag": "h6mJqHn33oCsDd5X57MI-g" } } ] } }
Also known as plaintext wallet.
This representation may be used without ever having a locked representation.
Implementations may choose to construct this representation from database entities.
{ "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/wallet/v1", ], "id": "http://example.gov/wallet/3732", "type": [ "UniversalWallet2020" ], "status": "UNLOCKED", "contents": [ // other wallet content types, ... { "id": "urn:uuid:e8fc7810-9524-11ea-bb37-0242ac130002", "title": "My Test Key 2", "image": "https://via.placeholder.com/150", "description": "For testing only, totally compromised.", "tags": ["professional", "organization", "compromised"], "correlation": ["4058a72a-9523-11ea-bb37-0242ac130002"], "controller": [ "did:key:z6MkjjCpsoQrwnEmqHzLdxWowXk5gjbwor4urC1RPDmGeV8r#z6MkjjCpsoQrwnEmqHzLdxWowXk5gjbwor4urC1RPDmGeV8r" ], "type": "Ed25519VerificationKey2018", "privateKeyBase58": "3CQCBKF3Mf1tU5q1FLpHpbxYrNYxLiZk4adDtfyPEfc39Wk6gsTb2qoc1ZtpqzJYdM1rG4gpaD3ZVKdkiDrkLF1p", "publicKeyBase58": "6GwnHZARcEkJio9dxPYy6SC5sAL6PxpZAB6VYwoFjGMU" } ] }
Interface functions are abstract, they take wallet contents and options as input, and they produce wallet contents and side effects as output.
In order to ensure portability, wallet interfaces MUST be functions of JSON, and not take complex instances of classes, functions or other types of object.
A wallet implementation MAY implement a subset of the interfaces defined below. For example:
Transfer
interface.
Also, the Query
interface of a verifiable credential wallet might be specific to credential search.Export
, Import
, Lock
, and/or Unlock
interfaces.Takes a serialized exported wallet representation as input. Loads the representation into wallet software.
This method may not be necessary for implementations that rely on external storage, such as Encrypted Data Vaults.
Only ciphertext wallet contents can be exported.
Produces a serialized exported wallet representation.
This method may not be necessary for implementations that rely on external storage, such as Encrypted Data Vaults.
Transforms one or more wallet contents from ciphertext to plaintext.
Requires knowledge of the password used to lock the wallet.
This method may not be necessary for implementations that rely on external storage, such as Encrypted Data Vaults.
Transforms one or more wallet contents from plaintext to ciphertext.
Requires knowledge of the password used to lock the wallet.
This method may not be necessary for implementations that rely on external storage, such as Encrypted Data Vaults.
Takes a Buffer as input, and an options
object, which
contains at least a verificationMethod
, and may content
additonal details such as alg
or other JOSE related
terms.
Must support detached signatures.
This method may not be necessary for implementations that rely on
other dedicated interface function to perform signing.
For example, a verifiable credential wallet that adds proofs using Issue
, Prove
interfaces might not implement this interface.
Takes a Buffer as input, and an options
object, which
contains at least a verificationMethod
, and may content
additonal details such as alg
or other JOSE related
terms.
Must support detached signatures.
This method may not be necessary for implementations that rely on
other dedicated interface functions to verify signatures.
For example, a verifiable credential wallet that can verify credential proofs using Verify
interface might not implement this interface.
Takes a Verifiable Credential or Verifiable Presentation as input,
returns a boolean verified
, and an error object
error
if verified
if false.
Takes a Verifiable Credential without a proof
, and an
options
object.
Produces a Verifiable Credential.
Here are the options that can be used to produce a verifiable credential:
let credential = {...} // a verifiable credential without proof let options = { verificationMethod: "did:example:1234#key-1", proofPurpose: "assertionMethod", created: "2017-06-18T21:19:10Z" controller: "did:example:1234", domain: "https://www.example.com", challenge: "0b4e419a-1410-4739-a58d-b37f4db10181", proofType: "Ed25519Signature2018" } let verifiableCredential = wallet.Issue(credential, options)
Takes a list of Verifiable Credentials ids, and an
options
object.
Produces a Verifiable Presentation.
Here are the options that can be used to produce a verifiable presentation:
let ids = [...] // ids of verifiable credentials let options = { verificationMethod: "did:example:1234#key-1", proofPurpose: "assertionMethod", created: "2017-06-18T21:19:10Z" controller: "did:example:1234", domain: "https://www.example.com", challenge: "0b4e419a-1410-4739-a58d-b37f4db10181", proofType: "Ed25519Signature2018" } let verifiableCredential = wallet.Prove(ids, options)
Takes a Currency, Key or Address and recipient options as input.
Produces a Connection, and transaction side effect.
Takes a Query and Type as input, and returns a collection of results based on current wallet contents.
Type input can be wallet implementation specific.
Since all universal wallet data models are JSON object types, here are the query types that can be supported:
let search = { "type": "QueryByFrame", "query": { "@context": { "@vocab": "http://example.org/" }, "@type": "Library", "contains": { "@type": "Book", "contains": { "@type": "Chapter" } } } } let results = wallet.Query(search)
let search = { "type": "PresentationExchange", "query": { "presentation_definition": { "id": "32f54163-7166-48f1-93d8-ff217bdb0653", "locale": "en-US", "input_descriptors": [{ "id": "name_input", "name": "Full Legal Name", "purpose": "We need your full legal name.", "schema": [ { "uri": "https://name-standards.com/name.json", "required": true } ] }] } } } let results = vcWallet.Query(search)
The following sections describe how a wallet controller can define relationships with external systems.
HD Wallets are a popular mechanism for managing many keys, addresess and accounts across multiple crypto currency ledgers.
Using a Meta Data object applied to a Secret, a user instruct an application to discover cryptocurrency that is controlled by a Secret.
See EIP84 for examples of how this is done in the ethereum community.
Keys can be exported from keyring and imported into wallets. Some transformation may be necessary.
gpg --armor --export you@example.com > publicKey.asc