Documentation
Everything, stated plainly
How the product works, what it protects, and exactly where the protection stops. If a claim is not backed by a check you can run, it is not in here.
Quick start
There is nothing to install and nothing to sign up for. Open the app, generate a pair of keys, and you have a meta-address you can hand out for the rest of the project’s life.
- 01Open the app. Go to the Ghost Receive tab and press Generate keys. Two private keys are created in your browser.
- 02Back them up. Download the JSON backup, or set a passphrase so the keys are encrypted at rest on this device.
- 03Share the meta-address. Copy the text or show the QR. It is safe to publish; it cannot spend anything.
- 04Get paid. Every payer derives a fresh one-time address from it. Claim their receipt QR, then sweep.
503 naming the exact variable, and the interface shows that message instead of a blank state.Keys and meta-address
RhMask implements ERC-5564 stealth addresses on secp256k1. You hold two private keys. The spending key moves funds. The viewing key only recognises which payments are yours, so it can be handed to an accountant without giving up control.
Your meta-address is the two matching public keys joined together:
st:eth:0x <33-byte spending pubkey> <33-byte viewing pubkey>
└─ 132 hex characters in totalA sender turns that into a one-time address nobody can link back to you:
ephemeral r, R = r·G
S = r · K_view (sender) == k_view · R (you)
h = keccak256(compress(S)), view tag = h[0]
P_stealth = K_spend + h·G
address = keccak256(uncompress(P_stealth)[1:])[12:]The view tag is one byte. Scanning checks it first and only does the full elliptic-curve work on a match, which is what keeps a scan fast once the announcer contract exists.
| Key | Can do | Cannot do |
|---|---|---|
| Spending key | Move funds from any stealth address | Nothing is out of reach; guard it |
| Viewing key | Find which payments belong to you | Spend anything |
| Meta-address | Receive payments | Spend, or reveal your balance |
Private Pay
A private payment is three scans and no server. Every step happens in a browser, and the receipt QR carries the announcement until the on-chain announcer contract ships.
| Step | Who | What happens |
|---|---|---|
| Request | Recipient | Builds a payment request from the meta-address, plus optional token, amount and memo. Shown as a link and a QR. |
| Send | Payer | Scans it, derives a one-time address, sends from any wallet on Robinhood Chain, receives a receipt QR. |
| Claim | Recipient | Scans the receipt. The viewing key verifies it, the spending key unlocks it, balances load. |
| Sweep | Recipient | Moves the funds anywhere, signed in the page with the derived key. |
Both formats are plain URLs, so a phone camera opens the right screen with no app install:
Payment request
https://rhmask.org/pay?to=st:eth:0x…&token=NVDA&amount=1.5&memo=invoice%2042
Receipt / announcement
https://rhmask.org/app?claim=1&addr=0x…&eph=0x…&tag=87&tx=0x…#receiveaddr is the one-time address, eph the compressed ephemeral public key, and tag the view tag. Those three fields map one-to-one onto the ERC-5564 announcement event, so the scanner will replace the QR without a format change.
Mask Swap
Swaps are filled through an intent router rather than a public order book, so the order never sits in a mempool as a visible trade. Pick an asset from 189 across 35 chains, enter a human amount, and the quote prints the venue and the flat fee before anything is sent.
The receiving address can be a fresh stealth address derived from your own meta-address in one click, so a swap and a private receive become a single action.
503 and the card shows dry quotes, clearly labelled.Security model
Five properties hold for every release, and each one is checked rather than asserted.
- Keys never leave the device. Generation, derivation and recognition are pure client-side code. No fetch sits in the key path.
- The server holds nothing. No custody, no private keys, no session. Secrets are server-only env vars used to reach third-party routers.
- Encrypted at rest. Optional passphrase wraps the keys with AES-256-GCM, key derived by PBKDF2-SHA256 over 310,000 rounds via WebCrypto.
- Fail closed. A missing key produces a named 503, never a silent fallback that might leak or mislead.
- Verified against mainnet. A read-only script simulates real transfers from real holders before each release. It signs nothing.
What is not hidden matters just as much: on-chain settlement is public, the venue filling a swap sees the deposit and the receiving address, and your IP reaches whichever RPC you use unless you run your own node.
Found a problem? Report it privately by email rather than in a public issue. Details are in SECURITY.md.
API reference
Every route is a Next.js handler in the same deployment. Reads are cached where it is safe, and nothing that touches a key is exposed.
| Method | Path | Notes |
|---|---|---|
GET | /api/health | Liveness and chain id |
GET | /api/chain | Chain params plus a live block number |
GET | /api/tokens | Stock token registry on Robinhood Chain |
GET | /api/router-tokens | Assets the intent router can fill, cached 10 minutes |
POST | /api/quote | Private fill quote; 503 when the router key is absent |
GET | /api/order/:deposit | Settlement status for a routed order |
GET | /api/vault | Vault totals, basket and proof ledger |
POST | /api/rpc | JSON-RPC pass-through, allow-listed read methods plus raw send |
The pass-through exists because some networks hijack the chain’s RPC domain at the DNS level. Routing through the app’s own origin keeps balance reads and sweeps working where the direct endpoint is filtered. Batches are capped and log ranges bounded so the public RPC is not abused through us.
curl -X POST https://rhmask.org/api/rpc \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}'Browser extension
A stealth address only protects you if you use it at the moment someone asks for an address. The extension moves that choice to exactly that moment: a chip appears beside any address field, one click pastes a fresh one-time address, and the receipt is kept locally.
It shares the key format with the app, so one backup and one passphrase work in both. It has no backend and requests no host permissions: the content script runs only on the tab where you clicked the toolbar icon.
git clone https://github.com/rh-mask/rhmask.git
cd rhmask && npm install
npm run build:extension # bundles into extension/dist
# chrome://extensions → Developer mode → Load unpacked → extension/distRun it yourself
The repository is public and the app builds with no secrets at all.
git clone https://github.com/rh-mask/rhmask.git
cd rhmask
npm install
npm run hooks:install # pre-push gate, once per clone
npm run dev # http://localhost:3000Four checks back the claims on this page, and the same set runs in CI:
| Command | What it proves |
|---|---|
npm run check:stealth | Derive, recognise, recover. A stranger cannot claim your payment. |
npm run check:payment | Request and receipt formats round-trip; malformed input is refused. |
npm run check:keycrypto | Seal and open keys; a wrong passphrase and a tampered blob both fail. |
npm run check:onchain | Read-only mainnet verification of tokens, stealth receive and vault feasibility. |
FAQ
›Is this a mixer?
No. Nothing is pooled and nothing is co-mingled. Each payment simply lands on its own fresh address that only you control.
›Do I need to connect a wallet?
Only to send. Generating keys, showing a request QR and claiming a receipt all work with no wallet at all.
›What if I clear my browser data?
Unswept balances become unreachable unless you have the backup file or the two private keys. Back them up first.
›Can I use it on my phone?
Yes. The request and receipt QRs are designed for a phone camera, and every screen is laid out for a small viewport.
›Why do I need ETH to sweep?
A fresh stealth address pays its own gas. The sponsored sweep on the roadmap removes that step.
›Is the vault live?
No. It is marked planned everywhere it appears, and it stays that way until a contract is deployed and audited.