Introduction

Imagine slipping a note inside a carbon-paper envelope and handing it to a notary. The notary stamps the outside, the stamp bleeds through the carbon paper onto your note inside, and when you open the envelope you have a certified document — one the notary never read. That is the intuition behind blind signatures, invented by David Chaum in 1982.

In Chaum's scheme, a bank signs a digital coin without ever seeing its serial number. Later, when you spend the coin, the merchant verifies the bank's signature — but neither the bank nor the merchant can link the spending back to the withdrawal. The result is cryptographically proven untraceability: the math itself guarantees the bank is blind, not just a policy promise.

Blind signatures sit at the intersection of two big ideas: public-key cryptography (RSA, 1977) and zero-knowledge thinking — using a mathematical blinding factor to hide a message while still allowing a valid signature to pass through. The technique is fully proven secure under standard RSA hardness assumptions, making it one of the few privacy tools backed by rigorous guarantees rather than hope.

Try It

The demo below walks through all four steps of the RSA blind-signature protocol. The arithmetic uses small numbers so every value stays visible — real deployments use 2048-bit keys.

<div class="protocol">
  <div class="params-row">
    <span class="label">{{pub_key_label}} <em>(n, e)</em>:</span>
    <span id="pubkey" class="val mono"></span>
    <span class="label">{{priv_key_label}} <em>d</em>:</span>
    <span id="privkey" class="val mono"></span>
  </div>
  <div class="steps">
    <div class="step" id="step-blind">
      <div class="step-head"><span class="badge">1</span> {{step1_head}}</div>
      <div class="step-body">
        <label>{{msg_label}} <em>m</em>: <input id="msg" type="number" min="2" max="90" value="17"></label>
        <label>{{rfactor_label}} <em>r</em>: <input id="rfactor" type="number" min="2" max="90" value="11"></label>
        <button id="btn-blind">{{btn_blind}}</button>
        <div class="result" id="res-blind"></div>
      </div>
    </div>
    <div class="step locked" id="step-sign">
      <div class="step-head"><span class="badge">2</span> {{step2_head}}</div>
      <div class="step-body">
        <div class="result" id="res-sign-input"></div>
        <button id="btn-sign" disabled>{{btn_sign}}</button>
        <div class="result" id="res-sign"></div>
      </div>
    </div>
    <div class="step locked" id="step-unblind">
      <div class="step-head"><span class="badge">3</span> {{step3_head}}</div>
      <div class="step-body">
        <div class="result" id="res-unblind"></div>
      </div>
    </div>
    <div class="step locked" id="step-verify">
      <div class="step-head"><span class="badge">4</span> {{step4_head}}</div>
      <div class="step-body">
        <div class="result" id="res-verify"></div>
        <button id="btn-verify" disabled>{{btn_verify}}</button>
        <div class="result" id="res-verify-out"></div>
      </div>
    </div>
  </div>
  <button id="btn-reset" class="ghost">{{btn_reset}}</button>
</div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; font-size: .93rem; }
.protocol { max-width: 520px; }
.params-row { display: flex; gap: 1rem; flex-wrap: wrap; background: #eef2f6; border-radius: 8px;
              padding: .5rem .8rem; margin-bottom: 1rem; font-size: .85rem; align-items: center; }
.label { color: #555; }
.val.mono { font-family: ui-monospace, monospace; font-weight: 700; color: #1d3557; }
.steps { display: flex; flex-direction: column; gap: .7rem; }
.step { border: 1px solid #cdd9e3; border-radius: 10px; overflow: hidden; }
.step.locked { opacity: .45; pointer-events: none; }
.step-head { display: flex; align-items: center; gap: .55rem; background: #f0f4f8;
             padding: .45rem .8rem; font-weight: 600; font-size: .88rem; }
.badge { display: inline-flex; align-items: center; justify-content: center;
         width: 1.5rem; height: 1.5rem; border-radius: 50%; background: #1d3557;
         color: #fff; font-size: .78rem; font-weight: 700; flex-shrink: 0; }
.step-body { padding: .6rem .8rem; display: flex; flex-direction: column; gap: .4rem; }
label { display: flex; align-items: center; gap: .4rem; font-size: .88rem; }
input[type=number] { width: 5rem; padding: .2rem .4rem; border: 1px solid #cdd9e3;
                     border-radius: 6px; font: inherit; text-align: center; }
button { font: 600 .85rem system-ui, sans-serif; padding: .38rem .8rem; border: 1px solid #1d3557;
         background: #1d3557; color: #fff; border-radius: 8px; cursor: pointer; align-self: flex-start; }
button.ghost { background: #fff; color: #1d3557; margin-top: .6rem; }
button:disabled { opacity: .4; cursor: not-allowed; }
.result { font-family: ui-monospace, monospace; font-size: .82rem; line-height: 1.6;
          background: #f7f9fb; border-radius: 6px; padding: .35rem .6rem; white-space: pre-wrap; }
.result:empty { display: none; }
.ok { color: #0a7d33; font-weight: 700; }
.bad { color: #c92f3c; font-weight: 700; }
.note { font-size: .8rem; color: #666; font-style: italic; }
// Code not found

Notice what happens at each step. The signer sees only the blinded message — a number that looks random, with no relationship to the original. After signing, you apply the inverse blinding factor and recover a valid signature. A verifier who knows only the signer's public key can confirm the signature is genuine — without knowing which blinding factor you used or when the signing happened.

The Real Complexity

Blind signatures have two security properties, and they come at different levels of strength:

  • Unforgeability: a user cannot produce a valid signed coin without the bank's cooperation. This relies on the RSA assumption — factoring large numbers is believed hard. It is the same assumption that secures HTTPS, so it is extremely well-tested, though technically still computational security (an all-powerful computer could break it).
  • Untraceability (blindness): the bank cannot link a signature it issued to the coin seen when it is spent. This property is unconditional — it holds even against a computationally unlimited bank. The blinding factor is chosen uniformly at random and is never revealed; the math guarantees the signer's view during withdrawal is statistically independent of the coin seen at payment.

The elegance is in that second point. Privacy here is not a policy — it is a mathematical theorem. Compare this with, say, a "privacy-friendly" payment system that promises not to log data: blind signatures give you the same guarantee without trusting anyone's word.

Chaum's construction uses only the multiplicative structure of RSA. To blind a message mm with blinding factor rr and public exponent ee, the user sends remmodnr^{e} \cdot m \bmod n. The signer returns ($r^{e}$ · m)^d mod n = r · $m^{d} \bmod n$. The user divides by rr and gets mdmodnm^{d} \bmod n — a valid RSA signature on mm. See how factoring and discrete log are at the heart of most cryptographic hardness.

Where It Matters

Blind signatures have moved far beyond their 1982 paper into real deployed systems:

  • eCash (DigiCash, 1989–1998): Chaum's own company deployed the first blind-signature digital cash. Banks issued blinded coins; merchants verified them; the bank was genuinely blind to who spent what. DigiCash failed commercially — not cryptographically — before the web was ready for e-commerce.
  • Anonymous e-voting: a blind signature from an election authority proves you are an eligible voter without recording which ballot you cast. This is the foundation of several modern e-voting protocols.
  • Privacy Pass (IETF, 2021): the standard used by Cloudflare and Apple to issue anonymous browser tokens that prove "this client solved a CAPTCHA" without linking tokens to IP addresses. It uses blind RSA signatures over HTTP.
  • Anonymous credentials: systems like U-Prove and GNU Taler use blind-signature descendants to let users prove attributes ("over 18", "paid subscriber") without revealing which account holds those attributes.
  • Post-quantum successors: lattice-based and hash-based blind signatures are active research areas, since RSA will break if large quantum computers become practical (see Shor's algorithm).

Every time you want an authority to certify something without building a surveillance log, blind signatures are the tool — or the inspiration behind the tool.

Conclusion

Blind signatures are a rare thing in privacy engineering: a mathematical proof of anonymity, not a promise. Chaum's 1982 trick — multiply by a random blinding factor, sign, divide it away — gives you a valid credential that the issuer is provably unable to trace.

The practical lesson outlasts any specific scheme. Whenever a system collects data "only for verification", ask whether blind signatures — or their modern lattice-based cousins — could do the same job without collecting anything at all. Sometimes the answer is yes, and the math lets you prove it.

For a deeper look at the hardness assumptions underneath, see factoring and the discrete log problem — the two pillars on which most classical cryptography stands.

Share this article

Pick a channel — or use your device's native share sheet.

Comments

Loading comments...

https://www.kipuhub.com/en/article/blind-signatures/Content licensed under CC BY-NC 4.0.