文章目录
BLS数字签名原理
一、概念须知
- 曲线哈希(Hashing to the curve)
- 曲线配对(curves pairing)
- 双线性配对特性(方便理解聚合签名)
e ( a ∗ b , p ) = e ( b , a ∗ p ) e(a*b,p)=e(b,a*p) e(a∗b,p)=e(b,a∗p)
e ( a , b + c ) = e ( a , b ) ∗ e ( a , c ) e(a,b+c)=e(a,b)*e(a,c) e(a,b+c)=e(a,b)∗e(a,c)
更加具体的介绍,网上很多,此处不赘述。
二、基础应用
2.1 单个签名
1、
p
k
pk
pk代表私钥,
P
=
p
k
∗
G
P=pk*G
P=pk∗G代表公钥,
m
s
g
msg
msg代表要签名的消息
2、签名:
S
i
g
=
p
k
∗
H
(
m
s
g
)
Sig=pk*H(msg)
Sig=pk∗H(msg) ,其中
H
(
m
s
g
)
H(msg)
H(msg)为
m
s
g
msg
msg经过哈希运算得到的摘要信息
2.2 单个签名验证
我们可以使用公钥
P
P
P来验证签名。
验证过程可理解为:验证 公钥 和 消息 的哈希值(曲线上的两点) 与 曲线基点
G
G
G(也称:生成点)和 签名(曲线上的另外两个点)是否映射到同一个数。
e
(
P
,
H
(
m
s
g
)
)
=
e
(
G
,
S
i
g
)
e(P,H(msg))=e(G,Sig)
e(P,H(msg))=e(G,Sig)
三、比特币中的应用
3.1 签名聚合
对于比特币来说,BLS极度优美。
一个区块中包含若干笔交易,每笔交易都有对应的签名(记为
s
i
g
n
sig_n
sign),将每笔交易的签名进行简单聚合,可得到聚合签名
S
i
g
Sig
Sig
S
i
g
=
S
i
g
1
+
S
i
g
2
+
S
i
g
3
+
.
.
.
+
S
i
g
n
Sig=Sig_1+Sig_2+Sig_3+...+Sig_n
Sig=Sig1+Sig2+Sig3+...+Sign
3.2 聚合签名验证
聚合签名验证即为验证:
e
(
G
,
S
i
g
)
=
e
(
P
1
,
H
(
m
s
g
1
)
)
∗
e
(
P
2
,
H
(
m
s
g
2
)
)
∗
.
.
.
∗
e
(
P
n
,
H
(
m
s
g
n
)
)
e(G,Sig)=e(P_1,H(msg_1))*e(P_2,H(msg_2))*...*e(P_n,H(msg_n))
e(G,Sig)=e(P1,H(msg1))∗e(P2,H(msg2))∗...∗e(Pn,H(msgn))
即:知晓聚合签名、签名者的公钥、和每笔交易的摘要信息,即可同时验证多比交易。
上述等式推导过程:(选择性观看)
e
(
G
,
S
i
g
)
=
e
(
G
,
S
i
g
1
+
S
i
g
2
+
S
i
g
3
+
.
.
.
+
S
i
g
n
)
=
e
(
G
,
p
k
1
∗
H
(
m
s
g
1
)
+
p
k
2
∗
H
(
m
s
g
2
)
+
.
.
.
+
p
k
n
∗
H
(
m
s
g
n
)
)
=
e
(
G
,
p
k
1
∗
H
(
m
s
g
1
)
)
∗
e
(
G
,
p
k
2
∗
H
(
m
s
g
2
)
)
∗
.
.
∗
e
(
G
,
p
k
n
∗
H
(
m
s
g
n
)
)
=
e
(
p
k
1
∗
G
,
H
(
m
s
g
1
)
∗
e
(
p
k
2
∗
G
,
H
(
m
s
g
2
)
∗
.
.
.
∗
e
(
p
k
n
∗
G
,
H
(
m
s
g
n
)
=
e
(
P
1
,
H
(
m
s
g
1
)
)
∗
e
(
P
2
,
H
(
m
s
g
2
)
)
∗
.
.
.
∗
e
(
P
n
,
H
(
m
s
g
n
)
)
e(G,Sig)\\=e(G,Sig_1+Sig_2+Sig_3+...+Sig_n)\\=e(G,pk_1*H(msg_1)+pk_2*H(msg_2)+...+pk_n*H(msg_n))\\=e(G,pk_1*H(msg_1))*e(G,pk_2*H(msg_2))*..*e(G,pk_n*H(msg_n))\\=e(pk_1*G,H(msg_1)*e(pk_2*G,H(msg_2)*...*e(pk_n*G,H(msg_n)\\=e(P_1,H(msg_1))*e(P_2,H(msg_2))*...*e(P_n,H(msg_n))
e(G,Sig)=e(G,Sig1+Sig2+Sig3+...+Sign)=e(G,pk1∗H(msg1)+pk2∗H(msg2)+...+pkn∗H(msgn))=e(G,pk1∗H(msg1))∗e(G,pk2∗H(msg2))∗..∗e(G,pkn∗H(msgn))=e(pk1∗G,H(msg1)∗e(pk2∗G,H(msg2)∗...∗e(pkn∗G,H(msgn)=e(P1,H(msg1))∗e(P2,H(msg2))∗...∗e(Pn,H(msgn))
应用聚合签名技术,可大大提升区块的验证速度!!!
四、联盟链中的应用
主要考虑应用到联盟链共识机制中,收集投票信息时采用!!!
可以降低主副节点间的通信复杂度!!!敲重点!!!
4.1 (m,m)多重签名
实际场景:系统内的所有节点需要针对一个信息(记为
m
s
g
msg
msg)进行投票
其中:
i - 节点私钥:
p
k
i
pk_i
pki
ii - 节点公钥:
P
i
=
p
k
i
∗
G
P_i=pk_i*G
Pi=pki∗G
1、聚合:
(1)聚合公钥:
P
=
p
k
1
+
p
k
2
+
.
.
.
+
p
k
n
P=pk_1+pk_2+...+pk_n
P=pk1+pk2+...+pkn
(ps:聚合公钥的计算方式有很多种,为了提升系统的安全系数,一般不会仅是进行加减法!!!本文方便理解,以加法为例。)
(2)聚合签名:
S
i
g
=
S
i
g
1
+
S
i
g
2
+
S
i
g
3
+
.
.
.
+
S
i
g
n
Sig=Sig_1+Sig_2+Sig_3+...+Sig_n
Sig=Sig1+Sig2+Sig3+...+Sign
2、签名验证:
即为验证:
e
(
G
,
S
i
g
)
=
e
(
P
,
H
(
m
s
g
)
)
e(G,Sig)=e(P,H(msg))
e(G,Sig)=e(P,H(msg))
推导:(选择性看)
e
(
G
,
S
i
g
)
=
e
(
G
,
S
i
g
1
+
S
i
g
2
+
.
.
.
+
S
i
g
n
)
=
e
(
G
,
(
p
k
1
+
p
k
2
+
.
.
.
+
p
k
n
)
∗
H
(
m
s
g
)
)
=
e
(
(
p
k
1
+
p
k
2
+
.
.
.
+
p
k
n
)
∗
G
,
H
(
m
s
g
)
)
=
e
(
P
1
+
P
2
+
.
.
.
+
P
3
,
H
(
m
s
g
)
)
=
e
(
P
,
H
(
m
s
g
)
)
e(G,Sig)\\=e(G,Sig_1+Sig_2+...+Sig_n)\\=e(G,(pk_1+pk_2+...+pk_n)*H(msg)) \\=e((pk_1+pk_2+...+pk_n)*G,H(msg))\\ =e(P_1+P_2+...+P_3,H(msg))\\=e(P,H(msg))
e(G,Sig)=e(G,Sig1+Sig2+...+Sign)=e(G,(pk1+pk2+...+pkn)∗H(msg))=e((pk1+pk2+...+pkn)∗G,H(msg))=e(P1+P2+...+P3,H(msg))=e(P,H(msg))
4.2 (m,n)多重签名(较复杂,重点)
实际场景:系统内的部分节点对一个信息进行投票。
同样:
i - 节点私钥:
p
k
i
pk_i
pki
ii - 节点公钥:
P
i
=
p
k
i
∗
G
P_i=pk_i*G
Pi=pki∗G
两个哈希函数:(注意区分)
i - 普通哈希函数
h
a
s
h
(
m
)
hash(m)
hash(m),结果为 一个 数字;
ii - 曲线哈希函数
H
(
x
)
H(x)
H(x),结果为曲线上的点!!!
步骤
1、初始化:保证签名者之后无需通信
(1)聚合公钥:
P
=
a
1
∗
P
1
+
a
2
∗
P
2
+
.
.
.
+
a
n
∗
P
n
P=a_1*P_1+a_2*P_2+...+a_n*P_n
P=a1∗P1+a2∗P2+...+an∗Pn
补充说明:关于
a
n
a_n
an,
a
n
a_n
an是一个数字,计算方式有多种,本文取
a
i
=
h
a
s
h
(
P
i
,
(
P
1
,
P
2
,
.
.
.
,
P
n
)
)
a_i=hash(P_i,(P_1,P_2,...,P_n))
ai=hash(Pi,(P1,P2,...,Pn))
(2)成员密钥:
成员密钥的作用:验证 该成员 确实是 签名组 (我自己起的名字,可能不太准确)内的成员!!!
M
K
i
=
(
a
1
∗
p
k
1
)
∗
H
(
P
,
i
)
+
(
a
2
∗
p
k
2
)
∗
H
(
P
,
i
)
+
.
.
.
+
(
a
n
∗
p
k
n
)
∗
H
(
P
,
i
)
MK_i=(a_1*pk_1)*H(P,i)+(a_2*pk_2)*H(P,i)+...+(a_n*pk_n)*H(P,i)
MKi=(a1∗pk1)∗H(P,i)+(a2∗pk2)∗H(P,i)+...+(an∗pkn)∗H(P,i)
成员密钥的验证: e ( G , M K i ) = e ( P , H ( P , i ) ) e(G,MK_i)=e(P,H(P,i)) e(G,MKi)=e(P,H(P,i))
推导:(选择性观看!!!)
e
(
G
,
M
K
i
)
=
e
(
G
,
(
a
1
∗
p
k
1
)
∗
H
(
P
,
i
)
+
(
a
2
∗
p
k
2
)
∗
H
(
P
,
i
)
+
.
.
.
+
(
a
n
∗
p
k
n
)
∗
H
(
P
,
i
)
)
=
e
(
G
,
(
a
1
∗
p
k
1
+
a
2
∗
p
k
2
+
.
.
.
+
a
n
∗
p
k
n
)
∗
H
(
P
,
i
)
)
=
e
(
(
a
1
∗
p
k
1
+
a
2
∗
p
k
2
+
.
.
.
+
a
n
∗
p
k
n
)
∗
G
,
H
(
P
,
i
)
)
=
e
(
a
1
∗
(
p
k
1
∗
G
)
+
a
2
∗
(
p
k
2
∗
G
)
+
.
.
.
+
a
n
∗
(
p
k
n
∗
G
)
,
H
(
P
,
i
)
)
=
e
(
a
1
∗
P
1
+
a
2
∗
P
2
+
.
.
.
+
a
n
∗
P
n
,
H
(
P
,
i
)
)
=
e
(
P
,
H
(
P
,
i
)
)
e(G,MK_i)\\=e(G,(a_1*pk_1)*H(P,i)+(a_2*pk_2)*H(P,i)+...+(a_n*pk_n)*H(P,i))\\=e(G,(a_1*pk_1+a_2*pk_2+...+a_n*pk_n)*H(P,i))\\=e((a_1*pk_1+a_2*pk_2+...+a_n*pk_n)*G,H(P,i))\\=e(a_1*(pk_1*G)+a_2*(pk_2*G)+...+a_n*(pk_n*G),H(P,i))\\=e(a_1*P_1+a_2*P_2+...+a_n*P_n,H(P,i))\\=e(P,H(P,i))
e(G,MKi)=e(G,(a1∗pk1)∗H(P,i)+(a2∗pk2)∗H(P,i)+...+(an∗pkn)∗H(P,i))=e(G,(a1∗pk1+a2∗pk2+...+an∗pkn)∗H(P,i))=e((a1∗pk1+a2∗pk2+...+an∗pkn)∗G,H(P,i))=e(a1∗(pk1∗G)+a2∗(pk2∗G)+...+an∗(pkn∗G),H(P,i))=e(a1∗P1+a2∗P2+...+an∗Pn,H(P,i))=e(P,H(P,i))
2、聚合签名
如果使用私钥
p
k
1
,
p
k
2
,
.
.
.
,
p
k
m
pk_1,pk_2,...,pk_m
pk1,pk2,...,pkm对交易进行签名,我们会生成m个签名:
S
i
g
1
=
p
k
1
∗
H
(
P
,
m
)
+
M
K
1
Sig_1=pk_1*H(P,m)+MK_1
Sig1=pk1∗H(P,m)+MK1
S
i
g
2
=
p
k
2
∗
H
(
P
,
m
)
+
M
K
2
Sig_2=pk_2*H(P,m)+MK_2
Sig2=pk2∗H(P,m)+MK2
…
S
i
g
m
=
p
k
m
∗
H
(
P
,
m
)
+
M
K
m
Sig_m=pk_m*H(P,m)+MK_m
Sigm=pkm∗H(P,m)+MKm
聚合签名:
(
S
′
,
P
′
)
=
(
S
i
g
1
+
S
i
g
2
+
.
.
.
+
S
i
g
m
,
P
1
+
P
2
+
.
.
.
.
+
P
m
)
(S',P')=(Sig_1+Sig_2+...+Sig_m,P_1+P_2+....+P_m)
(S′,P′)=(Sig1+Sig2+...+Sigm,P1+P2+....+Pm)
3、签名验证
(m,n)多重签名验证即为验证等式:
e
(
G
,
S
′
)
=
e
(
P
′
,
H
(
p
,
m
)
)
∗
e
(
P
′
,
H
(
P
,
1
)
+
H
(
P
,
2
)
+
.
.
.
+
H
(
P
,
m
)
)
e(G,S')=e(P',H(p,m))*e(P',H(P,1)+H(P,2)+...+H(P,m))
e(G,S′)=e(P′,H(p,m))∗e(P′,H(P,1)+H(P,2)+...+H(P,m))
推导:(选择性看!!!)
e
(
G
,
S
′
)
=
e
(
G
,
S
i
g
1
+
S
i
g
2
+
.
.
.
+
S
i
g
m
)
=
e
(
G
,
p
k
1
∗
H
(
P
,
m
)
+
p
k
2
∗
H
(
P
,
m
)
+
.
.
.
+
p
k
m
∗
H
(
P
,
m
)
+
M
K
1
+
M
K
2
+
.
.
.
+
M
K
m
)
=
e
(
G
,
p
k
1
∗
H
(
P
,
m
)
+
p
k
2
∗
H
(
P
,
m
)
+
.
.
.
+
p
k
m
∗
H
(
P
,
m
)
)
∗
e
(
G
,
M
K
1
+
M
K
2
+
.
.
.
+
M
K
m
)
=
e
(
G
∗
(
p
k
1
+
p
k
2
+
.
.
.
+
p
k
m
)
,
H
(
P
,
m
)
)
∗
e
(
G
,
(
a
1
∗
p
k
1
+
a
2
∗
p
k
2
+
.
.
.
+
a
m
∗
p
k
m
)
∗
(
H
(
P
,
1
)
+
H
(
P
,
2
)
+
.
.
.
+
H
(
P
,
m
)
)
)
=
e
(
P
′
,
H
(
P
,
m
)
)
∗
e
(
P
′
,
H
(
P
,
1
)
+
H
(
P
,
2
)
+
.
.
.
+
H
(
P
,
m
)
)
e(G,S')\\=e(G,Sig_1+Sig_2+...+Sig_m)\\=e(G,pk_1*H(P,m)+pk_2*H(P,m)+...+pk_m*H(P,m)+MK_1+MK_2+...+MK_m)\\=e(G,pk_1*H(P,m)+pk_2*H(P,m)+...+pk_m*H(P,m))*e(G,MK_1+MK_2+...+MK_m)\\=e(G*(pk_1+pk_2+...+pk_m),H(P,m))*\\e(G,(a_1*pk_1+a_2*pk_2+...+a_m*pk_m)*(H(P,1)+H(P,2)+...+H(P,m)))\\=e(P',H(P,m))*e(P',H(P,1)+H(P,2)+...+H(P,m))
e(G,S′)=e(G,Sig1+Sig2+...+Sigm)=e(G,pk1∗H(P,m)+pk2∗H(P,m)+...+pkm∗H(P,m)+MK1+MK2+...+MKm)=e(G,pk1∗H(P,m)+pk2∗H(P,m)+...+pkm∗H(P,m))∗e(G,MK1+MK2+...+MKm)=e(G∗(pk1+pk2+...+pkm),H(P,m))∗e(G,(a1∗pk1+a2∗pk2+...+am∗pkm)∗(H(P,1)+H(P,2)+...+H(P,m)))=e(P′,H(P,m))∗e(P′,H(P,1)+H(P,2)+...+H(P,m))
五、BLS的缺陷
1、配对函数不好得到;
2、配对消耗时间,签名验证不高效
六、JAVA简单实现
很早以前写的了,不保证能运行成功。
public class Pki<R, T> {
Map<ClientID,privkey>
public static Map<Integer, BigInteger> privKeys = new HashMap<>();//分私钥(PKI保存)
//Map<clientID,pubKey>
public static Map<Integer, Element> pubKeys = new HashMap<>();//分公钥(需要公布)
//Map<clientId,keyInfo>
public static Map<Integer, KeyInfo> keyInfos = new HashMap<>();
//初始化 - 一旦生成,就不可变!
public static final Pairing bp = PairingFactory.getPairing("a.properties");
public static final Field G1 = bp.getG1();
public static final Field Zr = bp.getZr();
public static final Element g = G1.newRandomElement().getImmutable();
public static final int CERTAINTY = 256;
public static final SecureRandom random = new SecureRandom();
//(Element)主公钥/主私钥
//(BigInteger)主私钥(Element)转换称为(BigInteger)形式,作为(secret)进行分割
private static final Element privateMaster = Zr.newRandomElement();//主私钥(私有)
public static final Element publicMaster = g.duplicate().powZn(privateMaster);//主公钥(目前没有什么作用)
private static final BigInteger secret = privateMaster.toBigInteger();
public static final BigInteger prime = new BigInteger(secret.bitLength() + 1, CERTAINTY, random);
public static void split(final BigInteger secret, int needed, int available, BigInteger prime, Random random) {
/*
* split(final BigInteger secret, int needed, int available, BigInteger prime, Random random)
* - secret - 待分割的秘密
* - needed - 几份可拼凑成完整的
* - available - 分成几份
* - prime - 大素数
* - random - 随机数
*
* 此函数执行后,会将:privKeys,pubKeys填满
* */
final BigInteger[] coeff = new BigInteger[needed];
coeff[0] = secret;
for (int i = 1; i < needed; i++) {
BigInteger r;
while (true) {
r = new BigInteger(prime.bitLength(), random);
//r>0 && r<prime
if (r.compareTo(BigInteger.ZERO) > 0 && r.compareTo(prime) < 0) {
break;//强制为+
}
}
coeff[i] = r;
}
for (int x = 1; x <= available; x++) {
BigInteger privKey = secret;
for (int exp = 1; exp < needed; exp++) {
privKey = privKey.add(coeff[exp].multiply(BigInteger.valueOf(x).pow(exp)));
}
privKeys.put(x, privKey);
Element pubKey = g.pow(privKey).getImmutable();
pubKeys.put(x, pubKey);
KeyInfo keyInfo = new KeyInfo(pubKey, privKey);
keyInfos.put(x, keyInfo);
}
}
}
KeyInfo
import it.unisa.dia.gas.jpbc.Element;
import java.math.BigInteger;
public class KeyInfo {
private Element publicKey;
private BigInteger privKey;
public KeyInfo() {
}
public KeyInfo(Element publicKey, BigInteger privKey) {
this.publicKey = publicKey;
this.privKey = privKey;
}
@Override
public String toString() {
return "KeyInfo{" +
"publicKey=" + publicKey +
", privKey=" + privKey +
'}';
}
public Element getPublicKey() {
return this.publicKey;
}
public void setPublicKey(Element publicKey) {
this.publicKey = publicKey;
}
public BigInteger getPrivKey() {
return this.privKey;
}
public void setPrivKey(BigInteger privKey) {
this.privKey = privKey;
}
}
-
关于属性是否私有的设置:public ,private
根据个人需要,自行设置即可!
一般要做数据传输的话,privateKey会设置成private(非全网可见),publicKey设置成public(全网可见) -
此程序存在一定的缺陷,此处列出:
1.关于prime,没有进行处理;只是简单实现了门限签名的原理
不添加prime,可以成功分割签名,但是做不到聚合签名验证,验证会出现不一致!实际与理想 差了一个mod prime!!! 如有需要,请自己补充!(ps:博主能力有限,想了好几天没搞出来)