Skip to content

盲签名

概述

  1. Setup: 签名者生成公私钥对 (pk,sk)
  2. Blind(m): 用户选择随机数 r,计算盲化消息 m=Blind(m,r) 并发送给签名者。
  3. Sign(sk,m): 签名者使用私钥 sk 对盲化消息 m 进行签名,生成盲签名 s=Sign(sk,m) 并返回给用户。
  4. Unblind(s,r): 用户使用随机数 r 对盲签名 s 进行去盲化,得到最终签名 s=Unblind(s,r)
  5. Verify(pk,m,s): 验证者使用公钥 pk 验证消息 m 和签名 s 的有效性。

主要应用于隐私保护,例如我有一个投票消息,需要签名者对其进行签名以证明其有效性,但不希望签名者知道具体内容,也不希望签名者能够将签名与我关联起来,就可以通过盲签名来实现。

RSA盲签名

  1. Setup: 签名者选择两个大素数 pq,计算 n=pq,计算 ed=1modϕ(n),其中 ϕ(n)=(p1)(q1)。公钥为 (e,n),私钥为 d
  2. Blind(m): 用户选择随机数 r,计算盲化消息 m=(mre)modn 并发送给签名者。
  3. Sign(d,m): 签名者使用私钥 d 对盲化消息 m 进行签名,生成盲签名 s=(m)dmodn 并返回给用户。
  4. Unblind(s,r): 用户使用随机数 r 对盲签名 s 进行去盲化,得到最终签名 s=(sr1)=mdmodn, s=mdred=mdrmodn
  5. Verify(e,n,m,s): 验证者计算 semodn==m

Schnorr盲签名

回顾:Schnorr签名

  1. Setup: 选择素数 p,q 使得 q(p1),取阶为 q 的生成元 g;设哈希 H:{0,1}Zq。私钥 xZq,公钥 y=gxmodp
  2. Sign(x,m): 签名者选随机数 kZq,计算 r=gkmodp,计算 c=H(Rm),计算 s=r+cxmodq,签名为 σ=(c,s)
  3. Verify(y,m,σ): 验证者计算 R=gsycmodp,检查 H(Rm)?=c
  4. 也可以令 σ=(r,s),验证时计算 c=H(Rm),然后计算 r=gsycmodp,检查 R?=R

具体步骤

原始版

  • alt text
  • alt text

优化版

  1. Setup: 选择素数 p,q 使得 q(p1),取阶为 q 的生成元 g;设哈希 H:{0,1}Zq。私钥 xZq,公钥 y=gxmodp
  2. Commit: 签名者选随机数 rZq,计算 R=grmodp,发送 R 给用户。
  3. Blind(m,R): 用户选盲化因子 α,βZq,计算 R=Rgαyβmodp,令 c=H(Rm),并令 c=c+βmodq,把 c 发给签名者。
  4. Sign(x,c): 签名者计算 s=r+cxmodq,返回 s
  5. Unblind(s,α): 用户计算 s=s+αmodq,得到最终签名 σ=(c,s)
  6. Verify(y,m,σ): 验证者计算 R=gsycmodp,检查 H(Rm)?=c

正确性:本质上是确认 R=R

R=gsyc=gs+αy(cβ)=gr+xc+αgx(c+β)=gr+α+xβ=Rgαyβ=R

BLS 盲签名

KeyGen

  1. Sample skZp
  2. Calc pk=gG2

Blind

  1. H=HashToG1(message)G1
  2. Sample rZp
  3. Blind the message: H=Hr

Sign

  1. Sign the blinded message: σ=Hsk

Unblind

  1. Unblind the signature: σ=σr1
  2. Obvoiusly obtain the signature on the original message: σ=Hsk

Verify

  1. Calc e(σ,G2)==e(HashToG1(message),pk)==e(H,G2)sk

BBS+

记双线性映射为
e:G1×G2GT,阶为素数 p
公开生成元 G1G1,G2G2
对消息数量为 L,为每个消息准备独立基点 HiG1,并有额外基点 H0G1

1. 签名者 - KeyGen

  1. Setup: G1,G2,GT,e,p,G1,G2,H0,H1,,HL
  2. Sample xZp(签名私钥)
  3. Calc and publish W=xG2G2(签名公钥)

2. 用户 - Blind(承诺被盲化消息)

设有消息向量 (m1,,mL),其中一部分要隐藏(盲签),也可有部分公开给签名者。

  1. 用户取随机盲化因子 rZp
  2. 计算承诺(对隐藏消息):C=rH0+iHmiHiG1其中 H 为隐藏消息下标集合。
  3. 用户给签名者发送:
    • 承诺 C
    • 公开消息 {mj}jR(若有),R 为公开下标集合
    • C 的“消息知晓证明”(PoK,证明其确实知道 r 与隐藏消息,防止恶意构造)

3. 签名者 - BlindSign

签名者验证用户 PoK 通过后:

  1. 采样随机 e,sZp
  2. 先组合公开消息项:Bpub=G1+jRmjHj
  3. 将用户承诺并入:B=Bpub+C
  4. 计算盲签名核心:A=(x+e)1(B+sH0)
  5. 返回盲签名:σ=(A,e,s)

4. 用户 - Unblind

用户收到 σ=(A,e,s) 后,用自己在承诺中使用的随机数 r 去盲:

  1. 计算s=s+r(modp)
  2. 得到最终 BBS+ 签名:σ=(A,e,s)

直观上,签名者签的是 B+sH0,而 B 里含有用户承诺的 rH0。去盲后把这部分并入 s


5. 验证者 - Verify

给定消息 (m1,,mL)、公钥 W、签名 σ=(A,e,s),验证:

  1. 计算B=G1+sH0+i=1LmiHi
  2. 检查双线性等式e(A,W+eG2)=?e(B,G2)
  3. 成立则验签通过。

正确性说明(简)

由签名构造

A=(x+e)1B

可得

(x+e)A=B

两边分别与 G2 做配对:

e(A,(x+e)G2)=e(B,G2)

又因 W=xG2,故 (x+e)G2=W+eG2,即

e(A,W+eG2)=e(B,G2)

验证式成立。

选择性披露与零知识证明(BBS+ Proof of Knowledge)

设签名为 σ=(A,e,s),消息为 (m1,,mL)
证明者想公开一部分消息 {mi}iD(disclosed),隐藏其余 {mi}iU(undisclosed),其中 DU={1,,L} 且不交。

目标:向验证者证明“我持有一个有效 BBS+ 签名,且公开消息值正确”,同时不泄露隐藏消息与签名本体可链接信息。

证明者 - ProofGen

  1. 随机重随机化签名(unlinkability)
    取随机 r1,r2Zp,计算

    A=r1A,A¯=r1Br2A,D=r1H0r2A

    其中

    B=G1+sH0+i=1LmiHi.

    这一步保证同一原始签名每次出示得到不同证明,防止关联。

  2. 把“签名关系”改写为线性知识关系
    可整理为(等价约束):

    A¯=iUmi(r1Hi)+s(r1H0)+1(r1G1+iDmir1Hi)r2A

    实际实现时通常将公开项移到常量侧,仅对秘密变量做 Schnorr 型 PoK。

  3. 承诺阶段(Sigma 协议第一步)
    对秘密变量(如 e,s,{mi}iU 及重随机化辅助量)采样随机掩码,构造承诺点 T1,T2,

  4. 挑战生成(Fiat-Shamir)

    c=H(ctxpkD,{mi}iDA,A¯,D,{Tk})

    其中 ctx 建议包含域分离标签、协议版本、会话 nonce(防重放)。

  5. 响应计算
    对每个秘密 w 输出响应

    zw=tw+cw(modp)

    得到证明

    π=(A,A¯,D,c,{zw},{mi}iD)

验证者 - ProofVerify

  1. 检查披露消息编码、下标集合 D 合法。
  2. π 中的 (A,A¯,D,{zw}) 重建各承诺 {Tk}(按验证方程)。
  3. 重新计算c=H(ctxpkD,{mi}iDA,A¯,D,{Tk})
  4. 验证 c=?c;一致则证明通过。
    这表示:存在隐藏消息与签名见证,使得公开消息与某个有效 BBS+ 签名一致。