Skip to content

Commit ddacb21

Browse files
andy-shi88capt4ce
authored andcommitted
31 block signature (#37)
* #31 add signature object to sign block
1 parent c8595ec commit ddacb21

12 files changed

+386
-51
lines changed

Gopkg.lock

Lines changed: 7 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Gopkg.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,8 @@
6060

6161
[[constraint]]
6262
branch = "master"
63-
name = "golang.org/x/net"
63+
name = "golang.org/x/net"
64+
65+
[[constraint]]
66+
branch = "master"
67+
name = "golang.org/x/crypto"

common/crypto/ed25519.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package crypto
2+
3+
import (
4+
"golang.org/x/crypto/ed25519"
5+
"golang.org/x/crypto/sha3"
6+
)
7+
8+
func ed25519GetPrivateKeyFromSeed(seed string) []byte {
9+
// Convert seed (secret phrase) to byte array
10+
seedBuffer := []byte(seed)
11+
// Compute SHA3-256 hash of seed (secret phrase)
12+
seedHash := sha3.Sum256(seedBuffer)
13+
// Generate a private key from the hash of the seed
14+
return ed25519.NewKeyFromSeed(seedHash[:])
15+
}

common/crypto/signature.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package crypto
2+
3+
import (
4+
"github.com/zoobc/zoobc-core/common/model"
5+
"github.com/zoobc/zoobc-core/common/query"
6+
"golang.org/x/crypto/ed25519"
7+
)
8+
9+
type (
10+
SignatureInterface interface {
11+
Sign(payload, accountID []byte, seed string) []byte
12+
SignBlock(payload []byte, nodeSeed string) []byte
13+
VerifySignature(payload, signature, accountID []byte) bool
14+
}
15+
16+
// Signature object handle signing and verifying different signature
17+
Signature struct {
18+
Executor *query.Executor
19+
}
20+
)
21+
22+
// NewSignature create new instance of signature object
23+
func NewSignature(executor *query.Executor) *Signature {
24+
return &Signature{
25+
Executor: executor,
26+
}
27+
}
28+
29+
// Sign accept account ID and payload to be signed then return the signature byte based on the
30+
// signature method associated with account.Type
31+
func (*Signature) Sign(payload, accountID []byte, seed string) []byte {
32+
// todo: Fetch account from accountID
33+
account := &model.Account{
34+
ID: []byte{4, 38, 68, 24, 230, 247, 88, 220, 119, 124, 51, 149, 127, 214, 82, 224, 72, 239, 56, 139,
35+
255, 81, 229, 184, 77, 80, 80, 39, 254, 173, 28, 169},
36+
AccountType: 0,
37+
Address: "BCZEGOb3WNx3fDOVf9ZS4EjvOIv_UeW4TVBQJ_6tHKlE",
38+
}
39+
switch account.AccountType {
40+
case 0: // zoobc
41+
accountPrivateKey := ed25519GetPrivateKeyFromSeed(seed)
42+
signature := ed25519.Sign(accountPrivateKey, payload)
43+
return signature
44+
default:
45+
accountPrivateKey := ed25519GetPrivateKeyFromSeed(seed)
46+
signature := ed25519.Sign(accountPrivateKey, payload)
47+
return signature
48+
}
49+
}
50+
51+
// SignBlock special method for signing block only, there will be no multiple signature options
52+
func (*Signature) SignBlock(payload []byte, nodeSeed string) []byte {
53+
nodePrivateKey := ed25519GetPrivateKeyFromSeed(nodeSeed)
54+
return ed25519.Sign(nodePrivateKey, payload)
55+
}
56+
57+
// VerifySignature accept payload (before without signature), signature and the account id
58+
// then verify the signature + public key against the payload based on the
59+
func (*Signature) VerifySignature(payload, signature, accountID []byte) bool {
60+
// todo: Fetch account from accountID
61+
account := &model.Account{
62+
ID: []byte{4, 38, 68, 24, 230, 247, 88, 220, 119, 124, 51, 149, 127, 214, 82, 224, 72, 239, 56, 139,
63+
255, 81, 229, 184, 77, 80, 80, 39, 254, 173, 28, 169},
64+
AccountType: 0,
65+
Address: "BCZEGOb3WNx3fDOVf9ZS4EjvOIv_UeW4TVBQJ_6tHKlE",
66+
}
67+
68+
switch account.AccountType {
69+
case 0: // zoobc
70+
result := ed25519.Verify(accountID, payload, signature)
71+
return result
72+
default:
73+
result := ed25519.Verify(accountID, payload, signature)
74+
return result
75+
}
76+
}

common/crypto/signature_test.go

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
package crypto
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
7+
"github.com/zoobc/zoobc-core/common/query"
8+
)
9+
10+
func TestNewSignature(t *testing.T) {
11+
type args struct {
12+
executor *query.Executor
13+
}
14+
tests := []struct {
15+
name string
16+
args args
17+
want *Signature
18+
}{
19+
{
20+
name: "NewSignature:success",
21+
args: args{
22+
executor: nil,
23+
},
24+
want: &Signature{
25+
Executor: nil,
26+
},
27+
},
28+
}
29+
for _, tt := range tests {
30+
t.Run(tt.name, func(t *testing.T) {
31+
if got := NewSignature(tt.args.executor); !reflect.DeepEqual(got, tt.want) {
32+
t.Errorf("NewSignature() = %v, want %v", got, tt.want)
33+
}
34+
})
35+
}
36+
}
37+
38+
func TestSignature_Sign(t *testing.T) {
39+
type fields struct {
40+
Executor *query.Executor
41+
}
42+
type args struct {
43+
payload []byte
44+
accountID []byte
45+
seed string
46+
}
47+
tests := []struct {
48+
name string
49+
fields fields
50+
args args
51+
want []byte
52+
}{
53+
{
54+
name: "Sign:valid",
55+
fields: fields{
56+
Executor: nil, // todo: update this when node-registration done.
57+
},
58+
args: args{
59+
payload: []byte{12, 43, 65, 65, 12, 123, 43, 12, 1, 24, 5, 5, 12, 54},
60+
accountID: []byte{4, 38, 68, 24, 230, 247, 88, 220, 119, 124, 51, 149, 127, 214, 82, 224, 72, 239, 56, 139,
61+
255, 81, 229, 184, 77, 80, 80, 39, 254, 173, 28, 169},
62+
seed: "concur vocalist rotten busload gap quote stinging undiluted surfer goofiness deviation starved",
63+
},
64+
want: []byte{42, 62, 47, 200, 180, 101, 85, 204, 179, 147, 143, 68, 30, 111, 6, 94, 81, 248, 219, 43, 90, 6, 167,
65+
45, 132, 96, 130, 0, 153, 244, 159, 137, 159, 113, 78, 9, 164, 154, 213, 255, 17, 206, 153, 156, 176, 206, 33,
66+
103, 72, 182, 228, 148, 234, 15, 176, 243, 50, 221, 106, 152, 53, 54, 173, 15},
67+
},
68+
}
69+
for _, tt := range tests {
70+
t.Run(tt.name, func(t *testing.T) {
71+
s := &Signature{
72+
Executor: tt.fields.Executor,
73+
}
74+
got := s.Sign(tt.args.payload, tt.args.accountID, tt.args.seed)
75+
if !reflect.DeepEqual(got, tt.want) {
76+
t.Errorf("Signature.Sign() = %v, want %v", got, tt.want)
77+
}
78+
})
79+
}
80+
}
81+
82+
func TestSignature_SignBlock(t *testing.T) {
83+
type fields struct {
84+
Executor *query.Executor
85+
}
86+
type args struct {
87+
payload []byte
88+
nodeSeed string
89+
}
90+
tests := []struct {
91+
name string
92+
fields fields
93+
args args
94+
want []byte
95+
}{
96+
{
97+
name: "SignBlock:success",
98+
fields: fields{
99+
Executor: nil, // todo: update when node-registration integrated
100+
},
101+
args: args{
102+
payload: []byte{12, 43, 65, 65, 12, 123, 43, 12, 1, 24, 5, 5, 12, 54},
103+
nodeSeed: "concur vocalist rotten busload gap quote stinging undiluted surfer goofiness deviation starved",
104+
},
105+
want: []byte{42, 62, 47, 200, 180, 101, 85, 204, 179, 147, 143, 68, 30, 111, 6, 94, 81, 248, 219, 43, 90, 6, 167,
106+
45, 132, 96, 130, 0, 153, 244, 159, 137, 159, 113, 78, 9, 164, 154, 213, 255, 17, 206, 153, 156, 176, 206, 33,
107+
103, 72, 182, 228, 148, 234, 15, 176, 243, 50, 221, 106, 152, 53, 54, 173, 15},
108+
},
109+
}
110+
for _, tt := range tests {
111+
t.Run(tt.name, func(t *testing.T) {
112+
s := &Signature{
113+
Executor: tt.fields.Executor,
114+
}
115+
if got := s.SignBlock(tt.args.payload, tt.args.nodeSeed); !reflect.DeepEqual(got, tt.want) {
116+
t.Errorf("Signature.SignBlock() = %v, want %v", got, tt.want)
117+
}
118+
})
119+
}
120+
}
121+
122+
func TestSignature_VerifySignature(t *testing.T) {
123+
type fields struct {
124+
Executor *query.Executor
125+
}
126+
type args struct {
127+
payload []byte
128+
signature []byte
129+
accountID []byte
130+
}
131+
tests := []struct {
132+
name string
133+
fields fields
134+
args args
135+
want bool
136+
}{
137+
{
138+
name: "VerifySignature:success", // todo: add fail:test after account integrated.
139+
fields: fields{
140+
Executor: nil, // todo: update this after account integrated
141+
},
142+
args: args{
143+
payload: []byte{12, 43, 65, 65, 12, 123, 43, 12, 1, 24, 5, 5, 12, 54},
144+
signature: []byte{42, 62, 47, 200, 180, 101, 85, 204, 179, 147, 143, 68, 30, 111, 6, 94, 81, 248, 219, 43, 90, 6, 167,
145+
45, 132, 96, 130, 0, 153, 244, 159, 137, 159, 113, 78, 9, 164, 154, 213, 255, 17, 206, 153, 156, 176, 206, 33,
146+
103, 72, 182, 228, 148, 234, 15, 176, 243, 50, 221, 106, 152, 53, 54, 173, 15},
147+
accountID: []byte{4, 38, 68, 24, 230, 247, 88, 220, 119, 124, 51, 149, 127, 214, 82, 224, 72, 239, 56, 139,
148+
255, 81, 229, 184, 77, 80, 80, 39, 254, 173, 28, 169},
149+
},
150+
want: true,
151+
},
152+
}
153+
for _, tt := range tests {
154+
t.Run(tt.name, func(t *testing.T) {
155+
s := &Signature{
156+
Executor: tt.fields.Executor,
157+
}
158+
if got := s.VerifySignature(tt.args.payload, tt.args.signature, tt.args.accountID); got != tt.want {
159+
t.Errorf("Signature.VerifySignature() = %v, want %v", got, tt.want)
160+
}
161+
})
162+
}
163+
}

core/service/blockService.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"fmt"
66
"math/big"
77

8+
"github.com/zoobc/zoobc-core/common/crypto"
9+
810
"github.com/zoobc/zoobc-core/common/contract"
911

1012
"github.com/zoobc/zoobc-core/common/query"
@@ -16,8 +18,8 @@ import (
1618
type (
1719
BlockServiceInterface interface {
1820
VerifySeed(seed *big.Int, balance *big.Int, previousBlock *model.Block, timestamp int64) bool
19-
NewBlock(version uint32, previousBlockHash []byte, blockSeed []byte, blocksmithID []byte,
20-
hash string, previousBlockHeight uint32, timestamp int64, totalAmount int64, totalFee int64, totalCoinBase int64,
21+
NewBlock(version uint32, previousBlockHash []byte, blockSeed []byte, blocksmithID []byte, hash string,
22+
previousBlockHeight uint32, timestamp int64, totalAmount int64, totalFee int64, totalCoinBase int64,
2123
transactions []*model.Transaction, payloadHash []byte, secretPhrase string) *model.Block
2224
NewGenesisBlock(version uint32, previousBlockHash []byte, blockSeed []byte, blocksmithID []byte,
2325
hash string, previousBlockHeight uint32, timestamp int64, totalAmount int64, totalFee int64, totalCoinBase int64,
@@ -33,22 +35,24 @@ type (
3335
Chaintype contract.ChainType
3436
QueryExecutor query.ExecutorInterface
3537
BlockQuery query.BlockQueryInterface
38+
Signature crypto.SignatureInterface
3639
}
3740
)
3841

3942
func NewBlockService(chaintype contract.ChainType, queryExecutor query.ExecutorInterface,
40-
blockQuery query.BlockQueryInterface) *BlockService {
43+
blockQuery query.BlockQueryInterface, signature crypto.SignatureInterface) *BlockService {
4144
return &BlockService{
4245
Chaintype: chaintype,
4346
QueryExecutor: queryExecutor,
4447
BlockQuery: blockQuery,
48+
Signature: signature,
4549
}
4650
}
4751

4852
// NewBlock generate new block
49-
func (*BlockService) NewBlock(version uint32, previousBlockHash, blockSeed, blocksmithID []byte,
50-
hash string, previousBlockHeight uint32, timestamp, totalAmount, totalFee, totalCoinBase int64,
51-
transactions []*model.Transaction, payloadHash []byte, secretPhrase string) *model.Block {
53+
func (bs *BlockService) NewBlock(version uint32, previousBlockHash, blockSeed, blocksmithID []byte, hash string,
54+
previousBlockHeight uint32, timestamp, totalAmount, totalFee, totalCoinBase int64, transactions []*model.Transaction,
55+
payloadHash []byte, secretPhrase string) *model.Block {
5256
block := &model.Block{
5357
Version: version,
5458
PreviousBlockHash: previousBlockHash,
@@ -62,11 +66,13 @@ func (*BlockService) NewBlock(version uint32, previousBlockHash, blockSeed, bloc
6266
Transactions: transactions,
6367
PayloadHash: payloadHash,
6468
}
69+
blockUnsignedByte, _ := core_util.GetBlockByte(block, false)
70+
block.BlockSignature = bs.Signature.SignBlock(blockUnsignedByte, secretPhrase)
6571
return block
6672
}
6773

6874
// NewGenesisBlock create new block that is fixed in the value of cumulative difficulty, smith scale, and the block signature
69-
func (*BlockService) NewGenesisBlock(version uint32, previousBlockHash, blockSeed, blocksmithID []byte,
75+
func (bs *BlockService) NewGenesisBlock(version uint32, previousBlockHash, blockSeed, blocksmithID []byte,
7076
hash string, previousBlockHeight uint32, timestamp, totalAmount, totalFee, totalCoinBase int64,
7177
transactions []*model.Transaction, payloadHash []byte, smithScale int64, cumulativeDifficulty *big.Int,
7278
genesisSignature []byte) *model.Block {

0 commit comments

Comments
 (0)