Blind Schnorr Signature Interactive Demo

What are blind signatures?
With regular schnorr signatures, a private key and nonce are used to sign a challenge for a message. The signature-nonce pair can then be verified against the signer's public key.

Blind signatures allow for a user to disguise a message and then request a server to sign this disguised message. The user can then take this signature and unblind it, resulting in an signature that is valid for the original message that is completely uncorrelated to what the server was asked to sign. Blind signatures are powerful for protecting user privacy, where a server can act as an authority/coordinator while remaining blind to the exact activity occuring.

See this fantastic article by Nadav for an intro on blind signatures and some motivations for the mathematics.

Follow the numbers 1-6

Get an idea for how blind schnorr signatures work. Actions taken by the signing server are on the left, and user's are on the right.


The server has a private key \(x\) and public key \(X = x*G\).
(\(G\) is the generator point of an elliptic curve - basically all you need to know is that it is impossible to find \(x\) from knowing \(X\)).

1. Generate a nonce

Server generates a random secret \(k\) and public nonce \(R=k*G\), and saves them.

Nonce \(R\):

4. Sign challenge

Request the server to produce a signature for the challenge using the nonce secret \(k\) and private key \(x\)
\(s = k + c'*x\).

  • Public Nonce \(R\):
  • Challenge \(c'\):

Signature \(s\):


2. Generate blindings

Choose a message \(m\) and generate three random scalar values \(\alpha, \beta, t\).
These scalars will used to blind (disguise) what we request the server to sign.

Blinding values:

  • \(\alpha\):
  • \(\beta\):
  • \(t\):

3. Apply blindings

Blind the nonce \(R' = R + \alpha*G + \beta*X\).

Blind the public key \(X' = X + t*G\).

For a message \(m\) create a challenge \(c = H(X', R', m)\) using a hash function \(H\), then blind it \(c' = c + \beta\).

Blinded nonce \(R'\):

Blinded pubkey \(X'\):

Challenge \(c'\):

5. Unblind signature

Use the blinding values to get the tweaked signature \(s' = s + \alpha + c*t\).

Signature \(s'\):

6. Verify signature

Once the user shares this signature-nonce pair, anyone can now verify that the signature-nonce pair \((s', R)\) solves the schnorr verification equation \(s' * G = R' + c*X'\) for some message \(m\) (see proof below).
Most importantly, the server has no way of correlating this signature-nonce pair with the challenge and nonce they signed with earlier.

  • Blinded Publickey:
  • Message:
  • Signature:
  • Blinded nonce:


Schnorr Verification Equation

Prove \((s', R')\) solves the schnorr verification equation \((s' * G = R' + c*X')\) for challenge \(c\) under public key \(X'\).

Hint: Expand \(s'\) from definitions (plug and chug algebra)

Starting with the blinded signature: $$\begin{aligned} s' &= s + \alpha + c * t \\ &= (k + c'*x) + \alpha + c * t \\ &= k + (c+\beta)*x + \alpha + c * t \\ &= (k + \alpha + \beta*x) + c*(x + t) \end{aligned}$$ so $$\begin{aligned} s'*G &= ((k + \alpha + \beta*x) + c*(x + t))*G \\ &= (k + \alpha + \beta*x)*G + c*(x + t)*G \\ &= k*G + \alpha*G + \beta*(x*G) + c*((x*G) + (t*G)) \\ &= (R + \alpha*G + \beta*X) + c*(X + t*G) \\ &= R' + c*X' \end{aligned}$$