What confidential Multi-Purpose Tokens (MPTs) on the XRP Ledger hide, and what they do not. A research project, shown on one snapshot of the Devnet.
The XRP Ledger is public: anyone can read every account and every transaction on it. Multi-Purpose Tokens (MPTs, XLS-33) are one of its kinds of token. Confidential Transfers (XLS-96) let an MPT holder keep their balance encrypted on that public ledger: hidden from the public, not from the token’s issuer.
Each confidential balance is stored as an ElGamal ciphertext: a number only the right key can read. A holder registers their own encryption key when they opt in.
The ledger must still check that nobody spends more than they hold. So every transaction that spends from a confidential balance carries zero-knowledge proofs, which every validator checks without learning any hidden amount.
XLS-96 is a final standard. When this page was written, on 2026-10-21, its amendment, ConfidentialTransfer, was enabled on Devnet and not on Mainnet or Testnet.
Sources: E-1, E-349; the README’s terms; TASK ZERO §3
ConfidentialBalanceInboxConfidentialBalanceSpendingConfidentialBalanceInboxConfidentialBalanceSpendingGreen is hidden from the public, not from the issuer: the issuer can read every green box, and so can an auditor if the token names one.
Convert (ConfidentialMPTConvert) moves tokens from the holder’s public balance into their confidential inbox, and the amount is published. The first Convert also registers the holder’s key, which can never be changed. Send (ConfidentialMPTSend) moves an amount from one confidential balance to another; the amount is hidden, the sender and receiver are not, and it too arrives in the receiver’s inbox. ConvertBack (ConfidentialMPTConvertBack) moves tokens back to a public balance, and the amount is published, on every ConvertBack separately.
Tokens in the inbox cannot be sent yet. A separate transaction, MergeInbox, moves the inbox into the spending balance, so a holder who converts must merge before their first Send.
Only Send hides an amount. The amount is encrypted separately for the sender, the receiver, the issuer and any auditor. Send’s proofs show that every copy is the same number, that the sender holds the key to their balance, and that neither the amount nor the sender’s remaining balance is negative.
Why are both ends public? The ledger shows that no tokens are created inside the confidential pool by keeping its total in plain view. The token records the total held in confidential form, and every Convert and ConvertBack changes it by a published amount.
Sources: E-9, E-33, F-24, F-27, P-4, P-11; TASK ZERO §3; WHAT-CONFIDENTIAL-MEANS
Both are hidden from the public, not from the issuer.
The public numbers also bound the hidden ones. If a holder converts in 500, receives nothing and converts back 400, anyone can work out that the other 100 is either still held or has left by confidential sends. No key is needed.
Sources: P-4, P-9, P-11, F-24, F-1, E-211, R-1, R-7
| who | Who sends to whom, and when | Amounts converted in or out | Total held in confidential form | A holder's balance | A Send's amount | Can spend a balance |
|---|---|---|---|---|---|---|
| Anyone | yes | yes | yes | only whether it is a recognisable zero | no | no |
| A holder | yes | yes | yes | their own; others only as a recognisable zero | their own only | their own, with both their keys |
| The issuer | yes | yes | yes | every one | every one | no; it can destroy one if the token allows clawback, and may freeze one |
| An auditor, if the token names one | yes | yes | yes | every one | every one | no |
Sources: P-9, E-58, E-11, E-33, E-118, E-119
The other pages do not show this facility. They read four Devnet test accounts that hold one demo token, made by this project while it was being built: Holder A, an active position; Holder B, whose key is derived from its master seed; Holder C, the account the project’s ed25519 signing ran on; and Holder D, an early test account. “What anyone sees” and “What the issuer sees” show how those accounts look to an observer and to the issuer. The facility below ran separately, and its record is in the repository: the facility walkthrough.
A bank pays a large buyer’s suppliers early, against their invoices. How much a supplier draws says a lot about its cash position, so these numbers are commercially sensitive.
This project built the core of that facility on XLS-96 and ran it on Devnet on 2026-08-25, in 28 validated facility transactions besides setting up the token:
The run shows that these transactions are well formed and that rippled accepts them. It read the ledger through a public Devnet node, not one on the same machine as the design requires, so it says nothing about that requirement.
The bank, as issuer, sees all of it.
In short, it hides how much each supplier draws and owes, not who borrows, when, or the size of the float.
Sources: E-146, B-18, E-151, F-24, F-26, R-1; the four accounts: E-208, E-118, E-176, E-101
This site only shows. The project itself runs on one machine: a Rust program, wconf-signer, holds the keys and signs, and everything else talks to it over a local socket that no web page can open.
Sources: the README’s “How it fits together”; E-146, B-15
Sources: P-10, E-9, E-119, E-341, E-12, E-21, E-223, E-290, E-292, P-5
Each id under a panel, such as E-58, is a row in the project’s claims register, CLAIMS.md. Where this page and a row disagree, the row wins.