跳到正文
chenxing
返回

高级签名协议:盲签名

高级签名协议概述

一般地,一个数字签名体制包括:密钥生成(keygen)、签名(sign)、验签(verify)。对普通签名体制的安全需求是,攻击者即使知道签名人的公钥和若干签名对的有效信息也无法伪造该签名人的有效签名。但是随着对数字签名的不断研究,以及电子商务、电子政务的快速发展,简单模拟手写签名的一般数字签名已不能完全满足现实中的应用需求,研究具有特殊性质或特殊功能的数字签名成为数字签名研究的主要方向。在密码学的研究中有许多学者提出了具有特定性质的数字签名,本次博客主要介绍其中的盲签名、群签名、环签名和基于身份的数字签名。

盲签名

盲签名的基本概念

在一个盲签名体制中存在两个参与实体:签名人和用户,其中,签名人拥有自己的公私钥,用户有一个消息mm,并希望得到签名人对mm的签名。一个盲签名方案一般由满足如下条件的3个算法Setup、Sign、Verify构成。

盲签名的安全性需求

盲签名的安全需求,通俗地说,我们称一个盲签名体制是安全的,它至少需要满足下面的3个性质:

盲签名的基本设计思路

假设用户有一个消息mm,并希望得到签名人对该消息的签名,一种比较典型的设计盲签名体制的做法是:

  1. 在发送消息给签名人之前,用户先引入盲化因子,由消息mm计算出数据mm^{'},发送mm^{'}给签名人,这个过程称为盲化。
  2. 签名人对mm^{'}执行签名操作得到签名ss^{'},发回给用户。
  3. 用户从ss^{'}中计算出消息mm的签名ss,这个过程称为去盲。

在签名过程中,签名人不知道消息mm是什么;在签名过后,如果把签名ss交给签名人,他不知道这是什么时候签的,也不知道是签给谁的。盲签名的这些良好特性使得它在如电子货币、电子拍卖、电子选举等诸多同时需要匿名性和认证性的应用场合起到关键作用,比如可以用来实现不可跟踪电子货币或无记名选举。

Chaum盲签名协议

在接下来的描述中,将参照教材的语言进行描述。“本节描述算法时使用电子选举的语言,方案适用于其他应用。选举委员会发布候选人名单,投票人在选票上标记自己的意向候选人。为了使得选票有效,该选票需要经过选举委员会签名确认。既要得到选举委员会对选票的签名,又不能泄露选票的内容,此时投票人可以和选举委员会交互执行盲签名协议。”

协议流程:

\begin{flalign} &Setup:\\ &\quad p,q = getPrime(safe.bit\_length);n = p * q;Pubkey = (n, e);Pravitekey = d\\ &Sign:\\ &\quad 盲化:USER\ choose\ k \in R[1,n - 1],compute\ m'\equiv m\cdot k^e(mod\ n),m'\rightarrow Signer\\ &\quad 签名:Signer\ compute\ s'\equiv (m')^d(mod\ n),s'\rightarrow USER\\ &\quad 去盲;USER\ compute\ s \equiv k^{-1}\cdot s'(mod\ n),(m,s)\rightarrow Verifier\\ &Verify:\\ &\quad return\quad s^e(mod \ n) == m& \end{flalign}
sequenceDiagram
participant U as User
participant S as Signer
Note over U: 计算 m' = kᵉ m mod n
U->>S: 发送 m'
Note over S: 计算 s' = m'ᵈ mod n
S->>U: 返回 s'
Note over U: 计算 s = k⁻¹ s' mod n

一次关于可关联性的错误思路

阅读教材时发现,在选举系统中,投票结束后会公开**(m,s),本人最初认为如果公开(m,s)就不再满足防追踪性(不可关联性)**。具体攻击(后续也证明这种思路是不可行的)思路如下:

\begin{flalign} &Target:选定一组(m',s'),若寻找到该(m',s')所对应的(m,s)则攻击成功.\\ &\quad 设公开的所有选民的(m,s)为(m,s)group.由m_i'\equiv m_i \cdot k_i^e(mod\ n);s_i'\equiv m_i^d\cdot k_i(mod\ n);s_i\equiv m_i^d(mod\ n)\rightarrow k_i\equiv s_i'\cdot s_i^{-1}(mod\ n)\\ &Attack:\\ &设选定(m_j',s_j')\\ &\quad for\ i \ in\ 1..num\\ &\quad\quad k' \equiv s_j' \cdot s_i^{-1}(mod\ n)\\ &\quad\quad if\ m_i\cdot (k_i')^e(mod\ n) \equiv m_j'\\ &\quad\quad\quad j\ is\ i\\ &攻击思路:由(m,s)group我们可以根据s与s'的关系,计算一个kgroup。\\ &针对于选定的(m',s'),只有与之对应的(m,s)计算的k_{temp}与当初USER选定的盲化因子相同,但其一定存在于我们计算的kgroup.\\ &事实正确确实如此,但是理想协议执行状态下Signer不可获取所有USER的k,因此,我尝试采用m'==m\cdot k_{guess}^e(mod\ n)来判定.\\ &但是结果并没有达到Target.原因如下:\\ &\quad k_{guess_{i}}\equiv s_j'\cdot s_i^{-1}(mod\ n)\rightarrow m_i\cdot k_{guess_{i}}^e(mod\ n)\equiv m_i\cdot (s_j')^e \cdot s_i^{-e}(mod\ n)\equiv m_i\cdot (m_j^d\cdot k_j)^e\cdot m_i^{-1}\equiv m_j\cdot k_j^e(mod\ n)\equiv m_j'\\ &故m_i\cdot k_{guess_{i}}^e\equiv m_j'恒成立,攻击失效. \end{flalign}
from Crypto.Util.number import getPrime, inverse
import random
###################### 初始化阶段 ######################
p = getPrime(512); q = getPrime(512)
n = p * q
e = 65537 # RSA加密常用公钥指数
phi = (p - 1) * (q - 1); d = inverse(e, phi)
###################### 预处理 ######################
# 设有100名人员参与投票
x = 100
# k_list为每位选票人员盲化时生成的随机数k, k ∈ [1, n - 1]
k_list = [random.randrange(1, n) for _ in range(x)]
# m_list为每为选票人员所投出去的票,为验证结果情况,取值为 1..100
m_list = [i for i in range(1, x + 1)]
###################### 签名阶段 ######################
# ss_list 存储选举委员会签名后的 s'; s_list存储最终提交的验证结果; mm_list存储盲化后的 m'
# 至此,我们有了 (m_list, s_list) 与 (mm_list, ss_list),前者对应教材公开后的(m, s); 后者对应选举委员会进行签名时收到的结果
# k_list并非 kgroup; 设 kk_list 表示公开(m,s)后委员会计算的 kgroup
ss_list = []; s_list = []; mm_list = []
for i in range(x):
m = m_list[i]; k = k_list[i]
# 盲化 mm 代替协议中的 m'
mm = m * pow(k, e, n) % n # m' = m * k ^ e (mod n)
ss = pow(mm, d, n) # s' = m' ^ d (mod n)
s = ss * inverse(k, n) % n
mm_list.append(mm); ss_list.append(ss); s_list.append(s)
###################### 验签阶段 ######################
# 若结果为 False ,输出 "Error" 后退出验证
for i in range(x):
m = m_list[i]; s = s_list[i]
if pow(s, e, n) != m:
print("Error")
break
###################### 攻击阶段 ######################
print("Attack begin.")
# 我们选取第 51 组的 (m', s'),找到其对应的(m, s)即攻击成功,即若后续结果校验时,在 i = 51 处显示正确,则说明攻击成功
mm = mm_list[51]; ss = ss_list[51]
# 1. 计算 kgroup
kk_list = []
for i in range(x):
s = s_list[i]
k_guess = ss * inverse(s, n) % n # k_guess = s' * s ^ {-1} (mod n)
kk_list.append(k_guess)
# 2. 令 m'' = m * k_guess ^ e (mod n) ,采用 m'' == m' 进行校验
for i in range(x):
m = m_list[i]
k = kk_list[i]
# mmm 表示当前计算的 m'', mm = m * k ^ e (mod n)
mmm = m * pow(k, e, n) % n
if mmm == mm:
print(f"The origin of (m', s') is {i}")
print("Attack over.")

代码实现

from Crypto.Util.number import getPrime, bytes_to_long
import random
class TA:
def __init__(self):
self.p, self.q = [getPrime(1024) for _ in range(2)]
self.n = self.p * self.q
self.e = 65537
phi = (self.p - 1) * (self.q - 1)
self.d = pow(self.e, -1, phi)
class USER:
def __init__(self, TA):
self.TA = TA
self.k = random.randrange(1, self.TA.n)
def blinding(self, message):
if isinstance(message, bytes):
message = bytes_to_long(message)
mm = message * pow(self.k, self.TA.e, self.TA.n) % self.TA.n
return mm
def unblinding(self, ss):
return pow(self.k, -1, self.TA.n) * ss
class Signer:
def __init__(self, TA):
self.TA = TA
def sign(self, mm):
return pow(mm, self.TA.d, self.TA.n)
class Verifier:
def __init__(self, TA):
self.TA = TA
def verify(self, mspair:tuple) -> bool:
m, s = mspair
if isinstance(message, bytes):
m = bytes_to_long(m)
return m == pow(s, self.TA.e, self.TA.n)
if __name__ == "__main__":
ta = TA()
user = USER(ta)
signer = Signer(ta)
verifier = Verifier(ta)
message = b'I choose Alice to go.'
mm = user.blinding(message)
ss = signer.sign(mm)
s = user.unblinding(ss)
flag = verifier.verify((message, s))
if flag:
print("Verify Successfully.")
else:
print("Error...")

基于离散对数的盲签名

教材提要

GG是一个阶为素数pp的乘法循环群,其上的CDH(computationalDiffieHellman)CDH(computational Diffie-Hellman)问题和DDH(decisionalDiffieHellman)DDH(decisional Diffie-Hellman)分别定义如下:

给定一个素数阶群GG,如果存在一个有效的算法VDDH()V_{DDH}(·)能够求解其上的DDHDDH问题,但不存在有效算法求解其上的CDHCDH问题,则将这样的群称为GDH(gapDiffieHellman)GDH(gap Diffie-Hellman)群。在2001年,斯坦福大学的3位学者BonehBonehLynnLynnShachamShacham利用GDHGDH群设计了一个短签名方案,以下称之为BLSBLS体制,该方案是这样工作的:GGGDHGDH群,G=p,H:{0,1}G|G|=p,H:\{0,1\}^{*}\rightarrow G^{*}为一个哈希函数,签名人选择xRZpx\leftarrow _R\mathbb{Z}_{p}^{*}作为自己的私钥,将ygxy\leftarrow g^x作为自己的公钥;对于任意消息mm,其数字签名为s=H(m)xs=H(m)^x;给定消息对(m,s)(m,s),如果VDDH(g,y,H(m),s)=1V_{DDH}(g,y,H(m),s)=1,则验证者接受签名有效,否则拒绝。

利用BLSBLS体制,容易得到一个GDHGDH群上的盲签名方案。这个工作是由BoldyrevaBoldyreva在2002年完成的。

协议流程

\begin{flalign} &1. Setup\\ &\quad 设G是一个阶为素数p的GDH群,g是它的任一生成元,H:\{0,1\}^*\rightarrow G^*为哈希函数,签名人Signer的公私钥为(y=g^x,x)\\ &2. Sign\\ &\quad 持有消息m的用户User为了获得签名人的签名,他与Signer执行如下交互,基于离散对数的盲签名:\\ &\quad ①盲化:User任选一随机数r,计算m'=g^rH(m),将m'发送给Signer;\\ &\quad ②签名:Signer计算s'=(m')^x,将结果返回给User;\\ &\quad ③去盲:User计算s=s'\cdot y^{-r},输出签名对(m,s).\\ &3. Verify\\ &\quad 给定Signer的公钥y和消息签名对(m,s),如果V_{DDH}(g,y,H(m),s)=1,则签名验证者相信这是Signer产生的有效签名。& \end{flalign}
sequenceDiagram
participant U as User
participant S as Signer
Note over U: 选择 r ←ᵣ Zₚ*<br/>计算 m' = gʳ H(m)
U->>S: 发送 m'
Note over S: 计算 s' = m'ˣ
S->>U: 返回 s'
Note over U: 计算 s = s' y⁻ʳ

双线性配对

在进行代码实现之前,对课本中提到的CDHCDHDDHDDH进行以下详细的解释,更加直观一些:

\begin{flalign} &GDH\\ &\quad CDH(计算Diffie-Hellman,即给定g^a和g^b,求解g^{ab})困难,但存在一个神奇的算法V_{DDH}(·),它能有效地解决\\ &\quad DDH问题(判定Diffie-Hellman,即给定g^a,g^b,h,判断h是否等于g^{ab}.& \end{flalign}

上述在描述协议时,只是在假设存在这样的一个VDDHV_{DDH}算法,然后基于这个假设去推导盲签名以及BLSBLS签名的安全性,至于这个VDDHV_{DDH}算法如何通过计算机实现,教材中并未提及。在计算机中,如何实现VDDHV_{DDH}就是一个问题,在已知的数学中,除了穷举,该如何构建一个能够防住CDHCDH又能有效解决DDHDDH的群?密码学界找了很久发现:配对友好型椭圆曲线上的双线性配对(Bilinear Piring),完美契合了这个要求。

双线性配对e(,)e(·,·)天然具有一个性质,它可以把指数上的乘法“提取”出来:e(ga,gb)=e(g,g)abe(g^a,g^b)=e(g,g)^{ab}。联系到教材中描述的,以及上方我简化的DDHDDH问题:给定公钥y=gx(ga)y=g^x(g^a),以及哈希点H(m)(gb)H(m)(g^b),验证者在那道签名ss,需要判断s==H(m)x(gab)s==H(m)^x(g^{ab}),所以如果我们用配对来实现,验证过程就会及其简单,我们只需要计算并对比两边的配对结果:left=e(g,s)left = e(g,s)right=e(y,H(m))right = e(y, H(m)),如果签名ss真的是用私钥xx签名所得,即s=H(m)xs=H(m)^x,那么e(g,s)=e(g,H(m)x)=e(g,H(m))x=e(gx,H(m))=e(y,H(m))e(g,s)=e(g, H(m)^x)=e(g,H(m))^x=e(g^x, H(m))=e(y, H(m))等式成立。这个计算配对的等式,就是在数学中抽象的VDDHV_{DDH}在计算机中的实现

为何CDHCDH依然困难?虽然配对能够依据上述等式来判断是否正确,但是它并不能帮你算出签名。配对的结果会落在另一个群GTG_T中,无法通过e(g,g)abe(g,g)^{ab}反推回原来的群元素gabg^{ab},这就实现了判定容易,计算困难GapGap属性。

代码实现

#include <pbc/pbc.h>
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
// 初始化配对环境
char param[1024] = "type a\nq 8780710799663312522437781984754049815806883199414208211028653399266475630880222957078625179422662221423155858769582317459277713367317481324925129998224791\nh 12016012264891146079388821366740534204802954401251311822919615131047207289359704531102844802183906537786776\nr 730750818665451621361119245571504901405976559617\nexp2 159\nexp1 107\nsign1 1\nsign0 1\n";
pairing_t pairing;
pairing_init_set_buf(pairing, param, strlen(param));
// 定义需要的元素
element_t g, x, y, Hm, r, M_prime, S_prime, r_inv, s, temp_left, temp_right;
// 初始化元素所在的群
element_init_G2(g, pairing);
element_init_G2(y, pairing);
element_init_G1(Hm, pairing);
element_init_G1(M_prime, pairing);
element_init_G1(S_prime, pairing);
element_init_G1(s, pairing);
element_init_Zr(x, pairing);
element_init_Zr(r, pairing);
element_init_Zr(r_inv, pairing);
element_init_GT(temp_left, pairing);
element_init_GT(temp_right, pairing);
cout << "Setup: keygen." << endl;
element_random(g); // 随机生成元g
element_random(x); // 私钥x
element_pow_zn(y, g, x); // 公钥y = g ** x
cout << "Interactive..." << endl;
// (1) 模拟消息哈希到群G1上的点Hm
element_random(Hm);
// (2) 盲化 M' = Hm ** r
element_random(r);
element_pow_zn(M_prime, Hm, r);
// (3) Signer sign message S' = (M') ** x
element_pow_zn(S_prime, M_prime, x);
// (4) User 去盲 s = (S') ** (r ** -1)
element_invert(r_inv, r); // 计算r的逆元
element_pow_zn(s, S_prime, r_inv); // 得到真实签名
cout << "Verify..." << endl;
// 验证e(s, g) == e(Hm, y)
element_pairing(temp_left, s, g);
element_pairing(temp_right, Hm, y);
if (!element_cmp(temp_left, temp_right)) {
cout << "验证成功,双线性配对等式成立。" << endl;
} else {
cout << "验证失败!" << endl;
}
// free the memory
element_clear(g);
element_clear(x);
element_clear(y);
element_clear(Hm);
element_clear(M_prime);
element_clear(S_prime);
element_clear(s);
element_clear(r);
element_clear(r_inv);
element_clear(temp_left);
element_clear(temp_right);
pairing_clear(pairing);
return 0;
}

部分盲签名

普通的盲签名体制中,被签名的消息完全由用户控制,签名人对此一无所知,也不知道关于最终签名的任何信息,这有可能造成签名被非法使用等问题。基于盲签名潜在的问题。部分盲签名缓解了相关问题,在一个部分盲签名方案中,签名人可以在签名中嵌入一个和用户实现约定好的公共信息。比如,在电子货币系统中银行可以将有效期作为公共信息嵌入电子货币,有效期过后所有电子货币均失效。这里还是采用教材中的例子,以ZhangZhang等人利用双线性配对设计的部分盲签名为例,介绍部分盲签名体制。与盲签名一样,一个部分盲签名体制也包括系统初始化算法SetupSetup、签名生成算法SignSign、签名验证算法VerifyVerify

协议流程

\begin{flalign} &1. Setup\\ &\quad 令q为一大素数,点P为q阶加法循环群G_1的生成元,G_2为同阶的乘法循环群,双线性映射e:G_1×G_1\rightarrow G_2,H:\{0,1\}^*\rightarrow \mathbb{Z}^*_q\\ &\quad 和H_0:\{0,1\}^*\rightarrow G_1为哈希函数,分别将任意比特串映射为\mathbb{Z}^*_q中的整数和G_1中的点。签名人Signer选择x\leftarrow _R\mathbb{Z}^*_q作为自己的私钥\\ &\quad 将P_{pub}\leftarrow xP公开作为自己的公钥.\\ &2.Sign\\ &\quad ①User与Signer约定一个公共信息c;\\ &\quad ②User选择一个随机数r,计算U\leftarrow H_0(m||c)+r(H(c)P+P_{pub}),其中"||"表示比特串级联,将U提交给签名人;\\ &\quad ③Signer利用自己的私钥x、公共信息c和接收到的U,计算V={1\over H(c)+x}U,将结果返回给User;\\ &\quad ④User计算S=V-rP,输出消息签名对(m||c,S)。\\ &3.Verify\\ &\quad 给定一个待验证的部分盲签名(m||c,S),验证者接受该签名当且仅当下式成立:\\ &\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad e(H(c)P+P_{pub},S)=e(P,H_0(m||c)).& \end{flalign}
sequenceDiagram
participant U as User
participant S as Signer
U<<->>S: 交互/协商公共信息 c
Note over U: 选择 r ←ᵣ Z_q*<br/>计算 U = H₀(m||c) + r(H(c)P + P_pub)
U->>S: 发送 U
Note over S: 计算 V = (H(c) + x)⁻¹ U
S->>U: 返回 V
Note over U: 计算 S = V - rP

正确性验证

\begin{flalign} &\quad e(H(c)P+P_{pub},S)\\ &=e((H(c)+x)P, V-rP)\\ &=e((H(c)+x)P, {1\over H(c) +x}U-rP)\\ &=e((H(c) +x)P,{H_0(m||c)+r(H(c)P+P_{pub})\over H(c)+x}-rP)\\ &=e((H(c)+x)P, {H_0(m||c)+r(H(c)P+P_{pub})\over H(c)+x})e((H(c)+x)P,-rP)\\ &=e(P,H_0(m||c)+r(H(c)P+P_{pub}))e(H(c)P+P_{pub},-rP)\\ &=e(P,H_0(m||c))e(P,r(H(c)P+P_{pub}))e(H(c)P+P_{pub},-rP)\\ &=e(P,H_0(m||c))& \end{flalign}
“一方面在产生$U$的过程中,由于$User$使用了随机数$r$,所以由此计算出的$U$是群$G_1$中的一个随机元素,签名者$Signer$无法从$U$和公共信息$c$中得到关于消息$m4的任何信息。另一方面,给定一个有效的消息签名对$(m||c,S)$,用户也无法私自将公共信息改成对自己有利的其他数据。对此,签名者可以拥有足够的自信。这是因为,如果$User$能够将$(m||c,S)$改为$(m||c',S)$的话,则下面两个式子同时成立”
{e(H(C)P+Ppub,S)=e(P,H0(mc))e(H(c)P+Ppub,S)=e(P,H0(mc))e((H(c)H(c))P,S)=e(P,H0(mc)H0(mc))\begin{cases} e(H(C)P+P_{pub},S)=e(P,H_0(m||c))\\ e(H(c')P+P_{pub},S)=e(P,H_0(m||c')) \end{cases}\rightarrow e((H(c')-H(c))P,S)=e(P,H_0(m||c')-H_0(m||c))

(H(c)H(c))S=H0(mc)H0(mc)(H(c')-H(c))S=H_0(m||c')-H_0(m||c),但是由于H()H(·)H0()H_0(·)都是哈希函数,这是计算上不可能的。因此,SignerSigner可以确幸用户无法修改公共信息。

代码实现

#include <pbc/pbc.h>
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
// 1. Setup 初始化对称配对环境 (Type A)
char param[1024] = "type a\nq 8780710799663312522437781984754049815806883199414208211028653399266475630880222957078625179422662221423155858769582317459277713367317481324925129998224791\nh 12016012264891146079388821366740534204802954401251311822919615131047207289359704531102844802183906537786776\nr 730750818665451621361119245571504901405976559617\nexp2 159\nexp1 107\nsign1 1\nsign0 1\n";
pairing_t pairing;
pairing_init_set_buf(pairing, param, strlen(param));
// 定义变量
element_t P, x, P_pub; // 基础参数
element_t hc, H0_mc; // 哈希值 H(c) 和 H0(m||c)
element_t r, U, V, S; // 盲化与签名变量
element_t temp_G1, temp_Zr, P_neg_r; // 临时计算变量
element_t left, right;
// 初始化群
element_init_G1(P, pairing);
element_init_G1(P_pub, pairing);
element_init_G1(H0_mc, pairing);
element_init_G1(U, pairing);
element_init_G1(V, pairing);
element_init_G1(S, pairing);
element_init_G1(temp_G1, pairing);
element_init_G1(P_neg_r, pairing);
element_init_Zr(x, pairing);
element_init_Zr(hc, pairing);
element_init_Zr(r, pairing);
element_init_Zr(temp_Zr, pairing);
element_init_GT(left, pairing);
element_init_GT(right, pairing);
cout << "1. Setup & KeyGen" << endl;
element_random(P); // 生成元
element_random(x); // sk
element_pow_zn(P_pub, P, x); // pk
cout << "2. Sign..." << endl;
// 模拟哈希函数输出
element_random(hc); // 模拟H(c) 输出Zr中的整数
element_random(H0_mc); // 模拟H0(m||c) 输出 G1 中的点
// User choose random r, compute U
element_random(r);
// conpute (P ** H(c)) * Ppub
element_pow_zn(temp_G1, P, hc);
element_mul(temp_G1, temp_G1, P_pub);
// conpute temp_G1 ** r
element_pow_zn(temp_G1, temp_G1, r);
// U = H0(m||c) * temp_G1
element_mul(U, H0_mc, temp_G1);
cout << "[User] send U to [Signer]..." << endl;
// Signer conpute V = U ** (1 / (hc + x))
element_add(temp_Zr, hc, x); // temp_Zr = hc + x
element_invert(temp_Zr, temp_Zr); // temp_Zr = (hc + x) ^ -1
element_pow_zn(V, U, temp_Zr); // V = U ** temp_Zr
cout << "[Signer] reply V to [User]..." << endl;
// User compute S = V * P ^ (-r)
element_neg(temp_Zr, r); // temp_Zr = -r
element_pow_zn(P_neg_r, P, temp_Zr); // P_neg_r = P ^ (-r)
element_mul(S, V, P_neg_r); // S = V * P_neg_r
cout << "[User] 完成去盲操作,输出签名S..." << endl;
cout << "3. Verify..." << endl;
// Verify e(P ** hc * Ppub, S) == e(P, H0_mc)
// 重新计算左侧配对的第一个参数 temp_G1 = P ** hc * Ppub
element_pow_zn(temp_G1, P, hc);
element_mul(temp_G1, temp_G1, P_pub);
element_pairing(left, temp_G1, S);
element_pairing(right, P, H0_mc);
if (!element_cmp(left, right)) {
cout << "Successfully Verify!" << endl;
} else {
cout << "Failed..." << endl;
}
// Free the memory
element_clear(P);
element_clear(P_pub);
element_clear(x);
element_clear(H0_mc);
element_clear(U);
element_clear(V);
element_clear(S);
element_clear(temp_G1);
element_clear(P_neg_r);
element_clear(hc);
element_clear(r);
element_clear(temp_Zr);
element_clear(left);
element_clear(right);
pairing_clear(pairing);
return 0;
}

写在最后

针对盲签名的学习,是第一次接触双线性配对,其实现原理比较复杂,但是对于上层调用而言并没有过多的难点。这里实现的过程中我采用的是PBC库进行的上层调用,目前应该是存在有更好用的一些库,这里并没有进行深究。其中对于代码实现中的一个问题就是,对于椭圆曲线中点的运算在映射回整数域的时候,其加法运算以及乘法运算会映射到乘法以及幂运算上。因此在阅读代码的时候,如果发现协议流程Code存在出入的话是正常的,后续没有使用Python去进行编程实现很大一部分原因是我的计算机上刚好存在PBC库,也不想花更多的经历去在sagemath中去配置环境了,所以存在前面所说的出入很大部分原因是PBC库有点老了的原因。😀😀

最后在这里写一下我对于盲签名的认知吧,其实对于所有的高级签名协议而言,我认为都是需求在驱动着研究。拿部分盲签名举个例子,我有一张钞票,如果我要花出去,商户需要确定这是一张经过银行认可的电子钞票,故其会接受,换句话说,认证成功才能实现电子钞票的最基本的功能。我既然需要银行来签名,就需要把钞票呈现给银行,如果没有盲签名,那么对于银行而言,他就可以跟踪用户“我”的开销,我这张钞票在哪里花了?买了什么?这属于用户的隐私,为了保证电子钞票的钞票职能以及用户的隐私,盲签名就可以完美解决这一问题,我用纸质的钞票去兑换电子钞票,此后这张钞票我如何花就不会被银行跟踪监测。

后续有时间会把群签名、环签名等高级签名协议也进行总结和编程复现验证一下。


分享到:

下一篇
关于这个博客