Disguise a Nostr event, blindly
sign, then unblind the signature and post it!
What are blind signatures?
In order to sign a message with regular
schnorr signatures, a secret key and a nonce (random number) are used to sign
a challenge for the message, producing a signature. This
signature-nonce pair can then be verified against the signer's
public key, proving the person signed off on the message using
their secret key.
Blind signatures allow for a user (you!) to disguise a message challenge
and then request a server to sign your disguised challenge. The user can
then take this signature and unblind it. Resulting in a signature that is
valid for the original challenge they disguised, while looking completely
different to the challenge which the server was asked to sign.
Blind signatures are powerful for protecting user privacy, where a
server can act as an authority or coordinator while remaining blind to the
exact details of what they are signing off on.
See this
fantastic article
by Nadav @ suredbits for an intro on blind signatures and some motivations
for the mathematics.
Follow steps 1-6
Let's create a message
(or Nostr post!), blind it, and ask
the Blind Schnorr Server to sign it. The server signs the disguised
challenge, and sends back a signature. We can then unblind this
signature, revealing a completely separate signature that is not only
valid but also looks completely unrelated to what we asked of the server.
In order to get a better idea for how blind schnorr signatures work,
interaction with the
signing server is on the left, and our
local computation is on the right
(WASM).
Server
The server has some 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 the secret
\(x\) from knowing \(X\)).
1. Generate a nonce
Server generates a new random secret \(k\) and uses it to create a
public nonce \(R=k*G\), and saves them.
User
2. Choose a message
Choose a message for the server to blindly sign \(m\),
(optional)
<Unsigned Nostr Event>
Message \(m\):
3. Generate blinding values
Generate two random scalar values \(\alpha\) and \(\beta\).
These scalars will used to blind (disguise) what we request the
server to sign.
🦀 These blinding values are generated locally in your browser
using WASM! 💻
Blinding values:
Alpha \(\alpha\):
Beta \(\beta\):
5. Sign blinded challenge
Request the server to produce a signature for the challenge using
the nonce secret \(k\) and private key \(x\)
\(s = k + c'*x\).
Signature \(s\):
4. Apply blindings
Blind the nonce \(R' = R + \alpha*G + \beta*X\).
For a message \(m\) create a challenge \(c = H(X, R', m)\) using a
hash function \(H\), then blind it \(c' = c + \beta\).
🦀 Use WASM to locally blind the nonce and create a challenge.
📝
Blinded nonce \(R'\):
Challenge \(c'\):
6. Unblind signature
Use the blinding values to get the tweaked signature \(s' = s +
\alpha\).
🦀 Locally unblind the signature!
Unblinded signature \(s'\):
7. Verify signature
Once the user shares this signature-nonce pair \((s', R)\), anyone
can verify it solves the schnorr verification equation \(s' * G =
R' + c*X'\) for some challenge \(c\) belonging to message \(m\).
Most importantly,
the server has no way of correlating this signature-nonce
pair with the challenge and nonce they signed with earlier.
Valid?:
Broadcast nostr event
<Signed Nostr Event>
Schnorr Verification Equation
Math: show \((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 the
algebra)
Why? To showcase some cool cryptography. I haven't yet
thought of any good reasons why you would want to post to Nostr
in this way. Though you could sell nonces for posting rights..
The previous version of this demo had no local client and
everything was computed serverside, which made no sense in
practice. Now there is separation between rocket rs API and
client WASM.
"Unlimited signing access is going to be chaos"
Yes but it may be fun to watch! What will you sign?
My nonce expired!: currently I have limited the server to
only allow one signing session at any one time. This is to
prevent
Wagner attacks, where concurrent signing sessions can allow for a forgery.
Did this help you understand blind schnorr signatures?
or did you just have fun posting anon under an open Nostr
account 🕵