0070 XLS-70d: On-Chain Verifiable Credentials #202
Replies: 2 comments 2 replies
-
Great Proposal. Just some thoughts in no order I would keep this all under the issuer. I don't own my drivers license or passport, thats exclusive property of the goverment. Same with a Financial Advisor approving accreditation status. That user cant take it or do anything with it. Intuitively I know the issuer and the user. I would look under the issuer, for the user's VC. But thats just me maybe there are examples where its reversed. I also think you should think about this in actual real world application. Take a DMV example. The issuer is the CA DMV. The verifier is the clerk, and the subject is me. The DMV needs to be able to add and remove clerks. That clerk is who is authorizing the VC. I need to know who authorized it. Under this each clerk is the issuer. Thats not really how I would structure this. Same for DEFI accreditation. The issuer is the organization, the verifier is the financial advisor, the subject is the client. I made an example how I would do this using smart contracts. https://github.com/Transia-RnD/xhs-library/blob/main/test/integration/did/did.test.ts I also wonder if URI is even necessary and the fact that it is not updatable makes me think it shouldn't be an actual URI. In the DMV example, I'm not going to store that PII information publicly. So it would most likely be an auth url. Which means that I can change the data anytime I want for the user, but also, sometimes url's change, maybe v1/v2 or maybe I just made a mistake and need to change them. I would store the Drivers License ID as the URI, then in whatever application I know where to look (the full url) if I need the details. But thats just me. I know there are others out there using these same principles. |
Beta Was this translation helpful? Give feedback.
-
How would a user know a |
Beta Was this translation helpful? Give feedback.
-
On-Chain Verifiable Credentials
Abstract
The XRPL DID (Digital Identifier) amendment (XLS-40) empowers users to manage their digital identities on the XRP Ledger. While this amendment adds support for on-chain identity management and simplifies off-chain credential usage, maximizing blockchain technology's full potential for credential handling requires on-chain solutions.
This document proposes a design to bridge this gap. It outlines the issuance, storage, and verification of credentials directly on the XRP Ledger, while still supporting the privacy needs of users.
On-chain credentialing can streamline various processes within the XRPL ecosystem. For example, financial institutions can issue verifiable credentials on the XRP Ledger, attesting to a user's identity and compliance. This eliminates the need for repeated KYC (Know Your Customer) checks across different platforms, fostering a smoother user experience. By enabling secure and verifiable credential management, this proposal unlocks the potential for a new wave of trust-based applications within the XRPL ecosystem.
1. Overview
This design adds support for creating, accepting, and deleting credentials. It also extends the existing Deposit Authorization feature, allowing accounts to not only whitelist specific accounts, but also whitelist accounts with specific credentials.
This proposal only supports blocking the interactions that Deposit Authorization supports, such as direct payments. However, future proposals could add support for credential-gating in other parts of the XRPL, such as AMMs or lending pools.
We propose modifying the
DepositPreauth
ledger object and theDepositPreauth
transaction, creating one new ledger object and three new transaction types:Credential
ledger objectCredentialCreate
transaction typeCredentialAccept
transaction typeCredentialDelete
transaction typeThis feature will require an amendment, tentatively titled
featureCredentialAuth
.1.1. Background: DIDs and Verifiable Credentials (VCs)
A verifiable credential (VC), as defined by the W3C specification, is a secure and tamper-evident way to represent information about a subject, such as an individual, organization, or even an IoT device. These credentials are issued by a trusted entity and can be verified by third parties without directly involving the issuer at all.
For a clearer understanding of the relationship between DIDs (Decentralized Identifiers) and VCs, a real-world example is considered. A DID serves as a unique identifier for an entity, similar to a fingerprint or a photo of a person (their physical characteristics). In contrast, a VC acts as a verifiable piece of information associated with that DID, much like a driver's license or passport. When a third party needs to verify an identity claim, they can examine the VC presented by the entity and ensure it aligns with the corresponding DID (such as comparing the photo on a driver's license to the physical characteristics of the person to whom it supposedly belongs).
1.2. Terminology
Note: These definitions do not directly match the definitions listed in the W3C Verifiable Credentials spec. These terms are used in a slightly different way in the context of this spec.
1.3. Basic Flow
In this scenario, an authorizer/verifier account, Verity, is a regulated entity wants to ensure that she is only interacting with properly KYC'd accounts.
2. On-Ledger Object:
DepositPreauth
The
DepositPreauth
object tracks a preauthorization from one account to another. This object already exists on the XRPL, but is being extended as a part of this spec to also support credential preauthorization.2.1. Fields
As a reference, here are the existing fields for the
DepositPreauth
object.Account
string
AccountID
Authorize
string
AccountID
LedgerEntryType
string
UInt16
0x0070
, mapped to the string"DepositPreauth"
, indicates that this is aDepositPreauth
object.OwnerNode
string
UInt64
Account.PreviousTxnID
.PreviousTxnID
string
Hash256
PreviousTxnLgrSeqNumber
number
UInt32
We propose these modifications:
Authorize
string
AccountID
AuthorizeCredential
object
Credential
2.1.1. Object ID
The ID of this object will be either a hash of the
Account
andAuthorize
fields (as it currently is), or a hash of theAccount
and the contents ofAuthorizeCredential
fields, combined with the unique space key forDepositAuth
objects:0x0070
.2.1.2.
Authorize
This field is now optional, and a valid
DepositPreauth
object must either have theAuthorize
field or theAuthorizeCredential
field.2.1.3.
AuthorizeCredential
The contents of this field determine the credential(s) that are accepted.
Issuer
string
AccountID
CredentialType
number
UInt32
3. On-Ledger Object:
AccountRoot
3.1. Fields
As a reference, here are the fields that the
AccountRoot
ledger object currently has.Account
string
AccountID
AccountTxnID
string
Hash256
AMMID
string
Hash256
Balance
string
Amount
BurnedNFTokens
number
UInt32
Domain
string
Blob
EmailHash
string
Hash128
FirstNFTokenSequence
number
UInt32
LedgerEntryType
string
UInt16
0x0061
, mapped to the stringAccountRoot
, indicates that this is anAccountRoot
object.MessageKey
string
Blob
MintedNFTokens
number
UInt32
NFTokenMinter
string
AccountID
OwnerCount
number
UInt32
PreviousTxnID
string
Hash256
PreviousTxnLgrSeq
number
UInt32
RegularKey
string
AccountID
Sequence
number
UInt32
TicketCount
number
UInt32
TickSize
number
UInt8
TransferRate
number
UInt32
WalletLocator
string
Hash256
WalletSize
number
UInt32
We propose these additional fields:
IssuedCredentials
number
UInt32
3.1.1.
IssuedCredentials
This value keeps track of how many credentials an account has issued. It is incremented every time an account creates (issues) a new credential, and decremented every time a credential issued by the account is deleted.
This enables the network to ensure that an issuer cannot delete their account if they have issued credentials still in existence.
4. On-Ledger Object:
Credential
This object will be an on-chain representation of a VC/verifiable credential, while ensuring that any sensitive details are kept off-chain, to protect the subject's privacy.
4.1. Fields
LedgerEntryType
string
UInt16
Credential
).Flags
number
UInt32
Subject
string
AccountID
Issuer
string
AccountID
CredentialType
number
UInt32
Expiration
number
UInt32
URI
string
Blob
OwnerNode
string
UInt64
Account.PreviousTxnID
.PreviousTxnID
string
Hash256
PreviousTxnLgrSeqNumber
number
UInt32
4.1.1. Object ID
The ID of this object will be a hash that incorporates the
Subject
,Issuer
, andCredentialType
fields, combined with a unique space key forCredential
objects, which will be defined during implementation.4.1.2.
Flags
lsfAccepted
0x00010000
lsfAccepted
is on if the subject of the credential has accepted the credential. If it is off, the issuer has the reserve burden; if it is on, the burden moves to the subject.4.1.3.
CredentialType
This value is similar to the NFT
Taxon
value, where the value's meaning will be decided by the issuer.5. Transaction:
DepositPreauth
This transaction currently creates and deletes
DepositPreauth
objects, thereby whitelisting and unwhitelisting accounts.This spec extends that functionality to also support whitelisting and unwhitelisting credentials.
5.1. Fields
As a reference, here are the existing fields for the
DepositPreauth
transaction:Authorize
string
AccountID
Unauthorize
string
AccountID
This proposal adds two new fields:
AuthorizeCredential
object
Credential
UnauthorizeCredential
object
Credential
5.2. Failure Conditions
DepositPreauth
will still be obeyed.Authorize
,Unauthorize
,AuthorizeCredential
, andUnauthorizeCredential
are included (i.e. there must be exactly one of these fields included).UnauthorizeCredential
is included in the transaction, the credential is not currently authorized.AuthorizeCredential
is included in the transaction:5.3. State Changes
DepositPreauth
object is created or deleted.6. Transaction:
CredentialCreate
Creates a
Credential
object. Must be done by the issuer.6.1. Fields
TransactionType
string
UInt16
CredentialCreate
).Account
string
AccountID
Subject
string
AccountID
CredentialType
number
UInt32
Expiration
number
UInt32
URI
string
Blob
6.2. Failure Conditions
Subject
doesn't exist.Expiration
is in the past.URI
field is too long (limit 256 bytes).6.3. State Changes
Credential
object is created.Issuer
==Account
, then thelsfAccepted
flag is enabled.7. Transaction:
CredentialAccept
This transaction transfers a credential from the
Issuer
to theAccount
. It is not a valid credential until it has been transferred.7.1. Fields
TransactionType
string
UInt16
CredentialAccept
).Account
string
AccountID
Issuer
string
AccountID
CredentialType
number
UInt32
7.2. Failure Conditions
Account
orIssuer
doesn't exist.Account
doesn't have enough reserve for the object.7.3. State Changes
lsfAccepted
flag is turned on in the credentialCredential
object is moved from the issuer's owner directory to the subject's8. Transaction:
CredentialDelete
This transaction deletes a
Credential
object.It can be executed by:
8.1. Fields
TransactionType
string
UInt16
CredentialDelete
).Account
string
AccountID
Subject
string
AccountID
Account
is assumed to be the subject.Issuer
string
AccountID
Account
is assumed to be the issuer.CredentialType
number
UInt32
8.2. Failure Conditions
Subject
,Issuer
, andCredentialType
fields doesn't exist.Account
isn't the issuer or account, and the expiration hasn't passed.8.3. State Changes
Credential
object is deleted.9. Transactions: Common Fields
9.1. Fields
As a reference, here are the fields that all transactions currently have.
CredentialID
string
Hash256
Transactions that accept this field:
Destination
field (like a payment) or something that has to be accepted by the destination (like an escrow/check).9.2. Failure Conditions
CredentialID
isn't an object that exists.CredentialID
isn't aCredential
object.CredentialID
is an expiredCredential
object.CredentialID
is included, but the destination doesn't have Deposit Authorization set up, or the transaction doesn't have a destination (e.g.AccountSet
).CredentialID
describes a credential that isn't authorized by the destination.9.3. State Changes
10. Invariants
10.1. Reserves
The burden of reserve should be with the issuer, and the credential should be in the issuer's owner directory, if the
lsfAccepted
flag is off. The burden of reserve should be with the subject and the credential should be in the subject's owner directory, if thelsfAccepted
flag is on.10.2.
IssuedCredentials
The
IssuedCredentials
value on an account should match the number of credentials actually issued by that account.10.3. The
DepositPreauth
ObjectA
DepositPreauth
ledger object always has exactly one of theAuthorize
field and theAuthorizeCredential
field.11. Example
In this example, a trusted issuer, Isabel, is issuing a credential that indicates that Alice is KYC'd. Verity is setting up her account to only interact with accounts that Isabel has attested to being properly KYC'd.
For ease of reading, some of the common transaction fields, such as signatures and public keys, have been left out of this example.
11.1.
CredentialCreate
Isabel creates the credential for Alice, after confirming her KYC status off-chain.
11.2. The
Credential
ObjectThis is the object created by the
CredentialCreate
transaction.11.3.
CredentialAccept
Alice accepts the credential, thereby making it valid.
11.4.
DepositPreauth
Verity sets up her account to only interact with accounts that Isabel has KYC'd.
11.5. Payments
This transaction will succeed, since Alice has attached the authorized credential from Isabel.
This transaction will fail, since Alice has not attached the authorized credential from Isabel. This is akin to trying to go through airport security without a form of ID.
This transaction will fail, since the attached credential isn't Bob's.
This transaction will fail, since Bob doesn't have a valid credential from Isabel.
This transaction will fail, since Bob doesn't have Deposit Authorization set up.
12. Security
12.1. Trust Assumptions
You need to trust the issuer to only be issuing valid credentials, and to not delete a credential without a legitimate reason.
12.2. Data Privacy
No private data needs to be stored on-chain (e.g. all the KYC data). The actual VC can still be stored off-chain. It could be stored at a link in the
URI
field.Appendix
Appendix A: FAQ
A.1: Do I have to only use credentials with the Deposit Authorization feature? Can I also use them for off-chain purposes?
You can use credentials for any purpose you'd like, not just for Deposit Authorization.
A.2: What data should be stored in the URI?
A metadata standard is needed. This proposal recommends using the W3C standard instead of making something bespoke for the XRPL.
A.3: Why not use NFTs instead, with a certain issuer-taxon combo and the
tfTransferable
flag unset?Using NFTs instead wouldn't be as elegant, since it means that the NFT has to follow a specific format. It would make more sense for an off-ledger use-case, not directly on-ledger. In addition, an NFT serves different needs - e.g. NFTs don't have an expiration.
A.4: Can an issuer issue a credential for themselves?
Yes.
A.5: Can an issuer edit the details of a credential once it's created?
No, it would have to be deleted and recreated. This is similar to needing to get a new card if your license/passport expires. If the
Subject
,Issuer
, andCredentialType
stay the same, though, the object will still have the same ID as before.A.6: Why do I need to include the
CredentialID
in my transaction? Shouldn't the XRPL be able to figure out whether I have a valid credential automatically?There is no way for the XRPL to iterate through just the list of credentials an account has; it can only iterate through the entire list of account objects. This is an unbounded list of objects (it could be millions of objects). Even just the list of accepted credentials could theoretically be millions of objects long. It could cause serious performance issues if the system had to iterate through the whole list.
It's much faster to have the credential ID included - it's easy to make sure that that's a valid credential, and check that it's an authorized credential.
A.7: Can a credential issuer delete their account?
No, a credential issuer cannot delete their account if they still have credentials in existence. They must delete all of their credentials first.
A.8: How do I get a list of credentials that an issuer has issued?
The answer to that question is still being investigated. One option would be a Clio API.
A.9: Why can't I save on reserves by storing a list of credentials I want to accept in
DepositPreauth.AuthorizeCredential
?For performance reasons, it is much easier to do a credential lookup if you can only have one credential per object. Otherwise, you'd have to search the whole list. In addition, people who need to use this feature will likely not find the object reserve cost-prohibitive.
A.10: Why are
CredentialCreate
andCredentialDelete
separate transactions?It's easier and clearer to have those be separate operations.
Beta Was this translation helpful? Give feedback.
All reactions