Blind RSA
Persona’s Privacy Pass protocol is built on Blind RSA Signatures (RFC 9474), a signature scheme that allows a server to sign a message without ever seeing its contents.
Why blind signatures?
In a standard RSA signature scheme, the signer sees the message before signing it. For Relay, this would mean Persona sees the exact token being issued — creating a correlation risk between issuance (where Persona knows your platform identity via API key) and redemption (which is meant to be anonymous).
Blind RSA breaks this link. Your client blinds the token input before sending it to Persona for signing. Persona signs the blinded message without seeing the underlying data. You then unblind the signature locally — producing a valid RSA signature that Persona cannot trace back to the issuance request.
The three operations
Blind RSA is defined by three operations (RFC 9474 §4):
Blind(publicKey, message)
Transforms a message into a blinded message using the signer’s public key and a random blinding factor. Returns:
blindedMsg— send this to the signerinv— the blinding inverse, kept secret on your end and used to unblind the response
BlindSign(privateKey, blindedMsg)
The signer’s operation — signs the blinded message without seeing the original. Returns a blindSig. This is what Persona does when you call POST /api/v1/privacy-passes.
Finalize(publicKey, message, blindSig, inv)
Unblinds the signature using inv. Returns a valid RSA-PSS signature over the original message — one that Persona produced without ever seeing.
Suite
Persona uses the RSABSSA-SHA384-PSS-Randomized suite:
Use a well-audited library that supports this suite. For TypeScript/Node.js, Cloudflare’s @cloudflare/blindrsa-ts implements RFC 9474 and supports RSABSSA-SHA384-PSS-Randomized directly.
Implementing blind RSA from scratch is strongly discouraged. Mistakes in blinding, padding, or unblinding can silently break the privacy guarantees of the protocol or produce signatures that fail verification. Proceed with a custom implementation at your own risk.

