
Blind notes
A note is a bearer claim on 0.004 USDG, signed by the pool without the pool ever seeing it. It is how a miner gets paid without a wallet, an account, or a link between the mining session and the payout.
Issuance
The suite is RSABSSA-SHA384-PSS-Randomized from RFC 9474 (RSA blind signatures), with a 2048-bit issuer key published at/api/v1/notes/key. For each note the miner's tab:
- draws 32 random bytes and prepares them (the randomized variant adds a 32-byte prefix),
- blinds the prepared message with the issuer's public key and a fresh blinding factor,
- sends the blinded bytes with its session id to
/api/v1/notes/mint.
The pool checks the session has 100 unspent verified shares per note, subtracts them in the same statement, and signs the blinded bytes. The tab unblinds the result into a standard RSA-PSS signature over the prepared message. The pool has seen only the blinded bytes, which are uniformly random to it.
Redemption
Anyone holding notes posts them with a payout address to /api/v1/notes/redeem, from any browser or script, at any time. The pool verifies each signature, then inserts each note's nullifier, the SHA-256 of its message, into a table with a unique key. A note whose nullifier is already there is refused: a note pays once. Up to 500notes per request.
Unlinkability, in practice
The signature hides the session. Timing and amounts can still correlate, so: redeem to an address that has never been used with this browser, wait some hours after a session, and redeem round numbers of notes. Notes can be exported as text and redeemed from another machine on /notes.
Verify a note yourself
const key = await fetch("/api/v1/notes/key").then(r => r.json());
const pk = await crypto.subtle.importKey("spki", b64(key.spki),
{ name: "RSA-PSS", hash: "SHA-384" }, false, ["verify"]);
const ok = await crypto.subtle.verify({ name: "RSA-PSS", saltLength: 48 },
pk, b64(note.s), b64(note.m));