Go语言门限签名示例

笔者不是很懂门限签名的原理,如果想要了解关于门限签名的原理,请搜索其它资源

门限签名简介:

( k , n ) \left( k,n\right)(k,n)门限签名模型中,所有节点都持有一个公共的 p u b l i c k e y publickeypublickey ,每一个节点 i ii 都有各自的私钥 p r i v a t e k e y i privatekey_{i}privatekeyi.

每一个副本 i ii 会用自己的 p r i v a t e k e y i privatekey_{i}privatekeyi 对一个信息(m)贡献部分签名

ρ i ← tsign ⁡ i ( m ) \rho_{i} \leftarrow \operatorname{tsign}_{i}(m)ρitsigni(m).

对于一个部分签名集合 { ρ i } i ∈ I \left\{\rho_{i}\right\}_{i \in I}{ρi}iI, 当∣ i ∣ = k |i|=ki=k时,就可以生成一个数字签名

σ ←  tcombine  ( m , { ρ i } i ∈ I ) \sigma \leftarrow \text { tcombine }\left(m,\left\{\rho_{i}\right\}_{i \in I}\right)σ tcombine (m,{ρi}iI)

其它节点可以用公共的 p u b l i c k e y publickeypublickey来验证数字签名是否正确

t v e r i f y ( m , σ , p u b l i c k e y ) tverify(m, \sigma, publickey)tverify(m,σ,publickey)

使用Go语言第三方库来实现门限签名

在一个拜占庭系统中, n = 3 f + 1 n=3f+1n=3f+1, 那么门限签名的阈值一般定义为 k = 2 f + 1 k=2f+1k=2f+1, 那么我们的门限签名模型为( k = 2 f + 1 , n = 3 f + 1 ) (k=2f+1, n=3f+1)(k=2f+1,n=3f+1).

Go语言中的第三方库kyber-tbls有关于门限签名的实现与测试,不过其测试代码中假设所有节点都不是拜占庭节点,本文将给出含有拜占庭节点的测试代码.在测试时,主要考虑两种情况,一种是节点掉线没有响应,一种是节点能正确的算出其部分签名,但在传输时恶意的将自己部分签名进行篡改后再发送给其它节点.

  1. 节点掉线

为了方便,定义一个结构体代表节点

type server struct {
	privateKey *share.PriShare   //节点的私钥
	publicKey  *share.PubPoly    //publicKey对于每个节点都一样
	message    []byte          
}

节点的初始化与部分签名

func makeServer(n, f, threshold int, suite *bn256.Suite) ([]server, [][]byte) {
	m := "hello"

	servers := make([]server, n)

	secret := suite.G1().Scalar().Pick(suite.RandomStream())
	priPoly := share.NewPriPoly(suite.G2(), threshold, secret, suite.RandomStream())
	pubPoly := priPoly.Commit(suite.G2().Point().Base())
	sigShares := make([][]byte, 0)

	for i, x := range priPoly.Shares(n) {

		servers[i].privateKey = x //将私钥赋予节点i
		servers[i].publicKey = pubPoly //将公钥赋予节点i
		servers[i].message = []byte(m)                                        
		sig, _ := tbls.Sign(suite, servers[i].privateKey, servers[i].message) //生成部分签名
		if i == f {
			continue //假设拜占庭节点为f=1,不会做出响应
		} else {
			sigShares = append(sigShares, sig) //生成数字签名
		}
	}
	return servers, sigShares
}

验证签名

func threshldVerify(servers []server, n, f, threshold int, suite *bn256.Suite, sigShares [][]byte, t *testing.T) []string {
	results := make([]string, n)
	for i := 0; i < n; i++ {
		sig, _ := tbls.Recover(suite, servers[i].publicKey, servers[i].message, sigShares, threshold, n)
		err := bls.Verify(suite, servers[i].publicKey.Commit(), servers[i].message, sig) //用公钥验证数字签名
		if err == nil {
			results[i] = "Success"
		} else {
			results[i] = "Fault"
		}
	}
	return results
}
  1. 节点发送篡改后的签名
    这一部分只需要将makeServer函数更改部分代码即可,拜占庭节点会篡改自己生成的部分签名
for i, x := range priPoly.Shares(n) {
	servers[i].privateKey = x //将私钥赋予节点i
	servers[i].publicKey = pubPoly
	servers[i].message = []byte(m)                                        //将公钥赋予节点i
	sig, _ := tbls.Sign(suite, servers[i].privateKey, servers[i].message) //生成部分签名
	if i == f {
		sig[0] ^= 0x10 //篡改自己生成的部分签名
	} else {
		sigShares = append(sigShares, sig) //生成数字签名
	}
}
return servers, sigShares

完整代码

package thresholdtest

import (
	"testing"

	"go.dedis.ch/kyber/v3/pairing/bn256"
	"go.dedis.ch/kyber/v3/share"
	"go.dedis.ch/kyber/v3/sign/bls"
	"go.dedis.ch/kyber/v3/sign/tbls"
)

type server struct {
	privateKey *share.PriShare
	publicKey  *share.PubPoly
	message    []byte
}

func makeServer(n, f, threshold int, suite *bn256.Suite) ([]server, [][]byte) {
	m := "hello"

	servers := make([]server, n)

	secret := suite.G1().Scalar().Pick(suite.RandomStream())
	priPoly := share.NewPriPoly(suite.G2(), threshold, secret, suite.RandomStream())
	pubPoly := priPoly.Commit(suite.G2().Point().Base())
	sigShares := make([][]byte, 0)

	for i, x := range priPoly.Shares(n) {

		servers[i].privateKey = x //将私钥赋予节点i
		servers[i].publicKey = pubPoly //将公钥赋予节点i
		servers[i].message = []byte(m)                                        
		sig, _ := tbls.Sign(suite, servers[i].privateKey, servers[i].message) //生成部分签名
		if i == f {
			sig[0] ^= 0x10
		} else {
			sigShares = append(sigShares, sig) //生成数字签名
		}
	}
	return servers, sigShares
}

func threshldVerify(servers []server, n, f, threshold int, suite *bn256.Suite, sigShares [][]byte, t *testing.T) []string {
	results := make([]string, n)
	for i := 0; i < n; i++ {
		sig, _ := tbls.Recover(suite, servers[i].publicKey, servers[i].message, sigShares, threshold, n)
		err := bls.Verify(suite, servers[i].publicKey.Commit(), servers[i].message, sig) //用公钥验证数字签名
		if err == nil {
			results[i] = "Success"
		} else {
			results[i] = "Fault"
		}
	}
	return results
}

func TestWithOneFailer(t *testing.T) {
	suite := bn256.NewSuite()
	n := 4
	f := 1
	threshold := 2*f + 1
	servers, sigShares := makeServer(n, f, threshold, suite)
	results := threshldVerify(servers, n, f, threshold, suite, sigShares, t)
	for i := range results {
		if results[i] != "Success" {
			t.Errorf("server [%d] recover fault.\n", i)
		}
	}
}

版权声明:本文为eye_water原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。