Implementation Verification
Use these test vectors to verify that your implementation produces correct output at each step. All vectors are derived from RFC 9474 Appendix A.1 (RSABSSA-SHA384-PSS-Randomized).
To reproduce blindedMsg exactly, your blind() implementation must accept
an injectable inv parameter (the modular inverse of the blinding factor
r). See RFC 9474 §4.2.
In production, inv is always generated randomly — only fix it for test
vector verification.
Test key pair
Use this public key for all test vector verification. Do not use in production.
The RFC 9474 test vectors reference raw key components (n, e, modLen)
directly. Our docs use publicKey as the argument to blind() and
finalize() — these components can be extracted from the public key PEM above
using any standard RSA library.
These values are extracted from the test public key above and needed if your implementation works with raw key components rather than a PEM file.
Test 1 — blind()
RSABSSA-SHA384-PSS-Randomized prepends a random 32-byte msg_prefix to the message before PSS encoding (prepared_msg = msg_prefix || msg).
Persona’s protocol does not use msg_prefix in production — the nonce in
tokenInput already provides per-request randomness. The msg_prefix here is
included solely to match the RFC 9474 Appendix A.1 test vectors exactly. It is
straightforward to pass through to your blind() call for verification
purposes.
Inputs
Construct preparedMsg by concatenating msg_prefix || msg, then call:
Expected output
Test 2 — finalize()
Inputs
Call finalize with the same preparedMsg from Test 1:
Expected output
Test 3 — buildTokenInput()
Parse this JSON response body and combine with the fixed nonce to produce the expected tokenInput.
Inputs
The challenge response:
Plus the fixed nonce you generate:
The decoded challenge JSON:
Extract mac from the decoded challenge and token-key-id from the JSON response body. Build tokenInput as:
Expected output

