【区块链】BLS数字签名算法介绍及拓展

文章目录

  • BLS数字签名原理
    • 概念须知
    • 基础应用
      • 单个签名
      • 单个签名验证
    • 比特币中的应用
      • 签名聚合
      • 聚合签名验证
    • 联盟链中的应用
      • (m,m)多重签名
      • (m,n)多重签名(较复杂,重点)
    • BLS的缺陷
  • JAVA简单实现

BLS数字签名原理

概念须知

  • 曲线哈希(Hashing to the curve)
  • 曲线配对(curves pairing)
  • 双线性配对特性(方便理解聚合签名)
    e ( a ∗ b , p ) = e ( b , a ∗ p ) e(a*b,p)=e(b,a*p) e(ab,p)=e(b,ap)
    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)

更加具体的介绍,网上很多,此处不赘述。


基础应用

单个签名

1、 p k pk pk代表私钥, P = p k ∗ G P=pk*G P=pkG代表公钥, m s g msg msg代表要签名的消息
2、签名: S i g = p k ∗ H ( m s g ) Sig=pk*H(msg) Sig=pkH(msg) ,其中 H ( m s g ) H(msg) H(msg) m s g msg msg经过哈希运算得到的摘要信息

单个签名验证

我们可以使用公钥 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)


比特币中的应用

签名聚合

对于比特币来说,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

聚合签名验证

聚合签名验证即为验证:
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,pk1H(msg1)+pk2H(msg2)+...+pknH(msgn))=e(G,pk1H(msg1))e(G,pk2H(msg2))..e(G,pknH(msgn))=e(pk1G,H(msg1)e(pk2G,H(msg2)...e(pknG,H(msgn)=e(P1,H(msg1))e(P2,H(msg2))...e(Pn,H(msgn))

应用聚合签名技术,可大大提升区块的验证速度!!!


联盟链中的应用

主要考虑应用到联盟链共识机制中,收集投票信息时采用!!!
可以降低主副节点间的通信复杂度!!!敲重点!!!

(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=pkiG

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))

(m,n)多重签名(较复杂,重点)

实际场景:系统内的部分节点对一个信息进行投票。
同样:
i - 节点私钥: p k i pk_i pki
ii - 节点公钥: P i = p k i ∗ G P_i=pk_i*G Pi=pkiG
两个哈希函数:(注意区分)
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=a1P1+a2P2+...+anPn
补充说明:关于 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=(a1pk1)H(P,i)+(a2pk2)H(P,i)+...+(anpkn)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,(a1pk1)H(P,i)+(a2pk2)H(P,i)+...+(anpkn)H(P,i))=e(G,(a1pk1+a2pk2+...+anpkn)H(P,i))=e((a1pk1+a2pk2+...+anpkn)G,H(P,i))=e(a1(pk1G)+a2(pk2G)+...+an(pknG),H(P,i))=e(a1P1+a2P2+...+anPn,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=pk1H(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=pk2H(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=pkmH(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,pk1H(P,m)+pk2H(P,m)+...+pkmH(P,m)+MK1+MK2+...+MKm)=e(G,pk1H(P,m)+pk2H(P,m)+...+pkmH(P,m))e(G,MK1+MK2+...+MKm)=e(G(pk1+pk2+...+pkm),H(P,m))e(G,(a1pk1+a2pk2+...+ampkm)(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
    public static Map<Integer, BigInteger> privKeys = new HashMap<>();//分私钥(PKI保存)
    //Map
    public static Map<Integer, Element> pubKeys = new HashMap<>();//分公钥(需要公布)
    //Map
    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
                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:博主能力有限,想了好几天没搞出来)

你可能感兴趣的:(区块链,区块链)