Skip to content

Commit 10f2a56

Browse files
committed
add vrf
1 parent c8a0c10 commit 10f2a56

File tree

8 files changed

+115
-69
lines changed

8 files changed

+115
-69
lines changed

README.md

-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# Algorand
22
Go implementation of Algorand algorithm. It's just a POC demo and cannot be used in PROD ENV.
33

4-
This demo has not implemented Verifiable Random Function(VRF), and all vrfs generation and verification success forever.
5-
64
## Docs
75
- [Algorand Analysis](docs/剖析Algorand.md)

algorand.go

+38-31
Original file line numberDiff line numberDiff line change
@@ -2,47 +2,52 @@ package main
22

33
import (
44
"bytes"
5-
"fmt"
6-
"github.com/pkg/errors"
5+
"errors"
76
"github.com/tinychain/algorand/common"
87
"gonum.org/v1/gonum/stat/distuv"
98
"math/big"
10-
"sync/atomic"
119
"time"
1210
)
1311

1412
var (
13+
log = common.GetLogger("algorand")
14+
1515
errCountVotesTimeout = errors.New("count votes timeout")
1616
)
1717

1818
type PID int
1919

2020
type Algorand struct {
2121
id PID
22-
pubkey atomic.Value
2322
privkey *PrivateKey
23+
pubkey *PublicKey
2424

2525
chain *Blockchain
2626
peer *Peer
2727
quitCh chan struct{}
2828
}
2929

3030
func NewAlgorand(id PID) *Algorand {
31+
pub, priv, _ := NewKeyPair()
3132
alg := &Algorand{
32-
id: id,
33-
chain: newBlockchain(),
33+
id: id,
34+
privkey: priv,
35+
pubkey: pub,
36+
chain: newBlockchain(),
3437
}
3538
alg.peer = newPeer(alg)
3639
return alg
3740
}
3841

3942
func (alg *Algorand) start() {
4043
alg.quitCh = make(chan struct{})
44+
GetPeerPool().add(alg.peer)
4145
go alg.run()
4246
}
4347

4448
func (alg *Algorand) stop() {
4549
close(alg.quitCh)
50+
GetPeerPool().remove(alg.peer)
4651
}
4752

4853
// round returns the latest round number.
@@ -65,21 +70,20 @@ func (alg *Algorand) tokenOwn() uint64 {
6570
}
6671

6772
// seed returns the vrf-based seed of block r.
68-
func (alg *Algorand) vrfSeed(round uint64) (seed, proof []byte) {
73+
func (alg *Algorand) vrfSeed(round uint64) (seed, proof []byte, err error) {
6974
if round == 0 {
70-
return alg.chain.genesis.Seed, nil
75+
return alg.chain.genesis.Seed, nil, nil
7176
}
7277
lastBlock := alg.chain.getByRound(round - 1)
7378
// last block is not genesis, verify the seed r-1.
7479
if round != 1 {
75-
var err error
7680
lastParentBlock := alg.chain.get(lastBlock.ParentHash, lastBlock.Round-1)
7781
if lastBlock.Proof != nil {
7882
// vrf-based seed
7983
pubkey := recoverPubkey(lastBlock.Signature)
8084
m := bytes.Join([][]byte{lastParentBlock.Seed, common.Uint2Bytes(lastBlock.Round)}, nil)
8185

82-
err = pubkey.VerifyVRF(lastBlock.Seed, lastBlock.Proof, m)
86+
err = pubkey.VerifyVRF(lastBlock.Proof, m)
8387
} else if bytes.Compare(lastBlock.Seed, common.Sha256(
8488
bytes.Join([][]byte{
8589
lastParentBlock.Seed,
@@ -90,11 +94,11 @@ func (alg *Algorand) vrfSeed(round uint64) (seed, proof []byte) {
9094
}
9195
if err != nil {
9296
// seed r-1 invalid
93-
return common.Sha256(bytes.Join([][]byte{lastBlock.Seed, common.Uint2Bytes(lastBlock.Round + 1)}, nil)).Bytes(), nil
97+
return common.Sha256(bytes.Join([][]byte{lastBlock.Seed, common.Uint2Bytes(lastBlock.Round + 1)}, nil)).Bytes(), nil, nil
9498
}
9599
}
96100

97-
seed, proof = alg.privkey.Evaluate(bytes.Join([][]byte{lastBlock.Seed, common.Uint2Bytes(lastBlock.Round + 1)}, nil))
101+
seed, proof, err = alg.privkey.Evaluate(bytes.Join([][]byte{lastBlock.Seed, common.Uint2Bytes(lastBlock.Round + 1)}, nil))
98102
return
99103
}
100104

@@ -111,17 +115,8 @@ func (alg *Algorand) sortitionSeed(round uint64) []byte {
111115
return alg.chain.getByRound(realR).Seed
112116
}
113117

114-
func (alg *Algorand) publicKey() *PublicKey {
115-
if pub := alg.pubkey.Load(); pub != nil {
116-
return pub.(*PublicKey)
117-
}
118-
pubkey := alg.privkey.PublicKey()
119-
alg.pubkey.Store(pubkey)
120-
return pubkey
121-
}
122-
123118
func (alg *Algorand) Address() common.Address {
124-
return common.BytesToAddress(alg.publicKey().Bytes())
119+
return common.BytesToAddress(alg.pubkey.Bytes())
125120
}
126121

127122
// run performs the all procedures of Algorand algorithm in infinite loop.
@@ -146,14 +141,16 @@ func (alg *Algorand) run() {
146141
// processMain performs the main processing of algorand algorithm.
147142
func (alg *Algorand) processMain() {
148143
currRound := alg.round() + 1
144+
log.Infof("node %d begin to perform consensus at round %d", alg.id, currRound)
149145
// 1. block proposal
150146
block := alg.blockProposal(false)
147+
log.Debugf("node %d init BA with block #%d %s", alg.id, block.Round, block.Hash())
151148

152149
// 2. init BA with block with the highest priority.
153150
consensusType, block := alg.BA(currRound, block)
154151

155152
// 3. reach consensus on a FINAL or TENTATIVE new block.
156-
fmt.Printf("reach consensus %d at round %d, block hash %s", consensusType, currRound, block.Hash())
153+
log.Infof("node %d reach consensus %d at round %d, block hash %s", alg.id, consensusType, currRound, block.Hash())
157154

158155
// 4. append to the chain.
159156
alg.chain.add(block)
@@ -175,12 +172,15 @@ func (alg *Algorand) processForkResolve() {
175172
func (alg *Algorand) proposeBlock() *Block {
176173
currRound := alg.round() + 1
177174

178-
seed, proof := alg.vrfSeed(currRound)
175+
seed, proof, err := alg.vrfSeed(currRound)
176+
if err != nil {
177+
return nil
178+
}
179179
blk := &Block{
180180
Round: currRound,
181181
Seed: seed,
182182
ParentHash: alg.lastBlock().Hash(),
183-
Author: alg.publicKey().Address(),
183+
Author: alg.pubkey.Address(),
184184
Time: time.Now().Unix(),
185185
Proof: proof,
186186
}
@@ -211,6 +211,7 @@ func (alg *Algorand) blockProposal(resolveFork bool) *Block {
211211
vrf, proof, subusers := alg.sortition(alg.sortitionSeed(round), role(iden, round, PROPOSE), expectedBlockProposers, alg.tokenOwn())
212212
// have been selected.
213213
if subusers > 0 {
214+
log.Debugf("node %d has %d sub-users selected as block proposer", alg.id, subusers)
214215
var (
215216
newBlk *Block
216217
proposalType int
@@ -222,13 +223,19 @@ func (alg *Algorand) blockProposal(resolveFork bool) *Block {
222223
newBlk = alg.proposeFork()
223224
proposalType = FORK_PROPOSAL
224225
}
226+
if newBlk == nil {
227+
return &Block{
228+
Round: round,
229+
ParentHash: alg.lastBlock().Hash(),
230+
}
231+
}
225232
proposal := &Proposal{
226233
Round: newBlk.Round,
227234
Hash: newBlk.Hash(),
228235
Prior: maxPriority(vrf, subusers),
229236
VRF: vrf,
230237
Proof: proof,
231-
Pubkey: alg.publicKey().Bytes(),
238+
Pubkey: alg.pubkey.Bytes(),
232239
}
233240
alg.peer.setMaxProposal(round, proposal)
234241
blkMsg, _ := newBlk.Serialize()
@@ -264,14 +271,14 @@ func (alg *Algorand) blockProposal(resolveFork bool) *Block {
264271

265272
// sortition runs cryptographic selection procedure and returns vrf,proof and amount of selected sub-users.
266273
func (alg *Algorand) sortition(seed, role []byte, expectedNum int, weight uint64) (vrf, proof []byte, selected int) {
267-
vrf, proof = alg.privkey.Evaluate(constructSeed(seed, role))
274+
vrf, proof, _ = alg.privkey.Evaluate(constructSeed(seed, role))
268275
selected = subUsers(expectedNum, weight, vrf)
269276
return
270277
}
271278

272279
// verifySort verifies the vrf and returns the amount of selected sub-users.
273280
func (alg *Algorand) verifySort(vrf, proof, seed, role []byte, expectedNum int) int {
274-
if err := alg.publicKey().VerifyVRF(vrf, proof, constructSeed(seed, role)); err != nil {
281+
if err := alg.pubkey.VerifyVRF(proof, constructSeed(seed, role)); err != nil {
275282
return 0
276283
}
277284

@@ -411,7 +418,7 @@ func (alg *Algorand) binaryBA(round uint64, hash common.Hash) common.Hash {
411418
func (alg *Algorand) countVotes(round uint64, step int, threshold float64, expectedNum int, timeout time.Duration) (common.Hash, error) {
412419
expired := time.NewTimer(timeout)
413420
counts := make(map[common.Hash]int)
414-
voters := make(map[PublicKey]struct{})
421+
voters := make(map[string]struct{})
415422
it := alg.peer.voteIterator(round, step)
416423
for {
417424
msg := it.next()
@@ -426,10 +433,10 @@ func (alg *Algorand) countVotes(round uint64, step int, threshold float64, expec
426433
voteMsg := msg.(*VoteMessage)
427434
votes, hash, _ := alg.processMsg(msg.(*VoteMessage), expectedNum)
428435
pubkey := voteMsg.RecoverPubkey()
429-
if _, exist := voters[*pubkey]; exist || votes == 0 {
436+
if _, exist := voters[string(pubkey.pk)]; exist || votes == 0 {
430437
continue
431438
}
432-
voters[*pubkey] = struct{}{}
439+
voters[string(pubkey.pk)] = struct{}{}
433440
counts[hash] += votes
434441
// if we got enough votes, then output the target hash
435442
if uint64(counts[hash]) >= uint64(float64(expectedNum)*threshold) {

blockchain.go

+30-8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"encoding/json"
66
"github.com/tinychain/algorand/common"
7+
"math/rand"
78
"sync"
89
"time"
910
)
@@ -24,14 +25,32 @@ type Block struct {
2425
}
2526

2627
func (blk *Block) Hash() common.Hash {
27-
return common.Sha256(bytes.Join([][]byte{
28+
data := bytes.Join([][]byte{
2829
common.Uint2Bytes(blk.Round),
2930
blk.ParentHash.Bytes(),
30-
blk.Author.Bytes(),
31-
common.Uint2Bytes(uint64(blk.Time)),
32-
blk.Seed,
33-
blk.Proof,
34-
}, nil))
31+
}, nil)
32+
33+
if !blk.Author.Nil() {
34+
data = append(data, bytes.Join([][]byte{
35+
blk.Author.Bytes(),
36+
blk.AuthorVRF,
37+
blk.AuthorProof,
38+
}, nil)...)
39+
}
40+
41+
if blk.Time != 0 {
42+
data = append(data, common.Uint2Bytes(uint64(blk.Time))...)
43+
}
44+
45+
if blk.Seed != nil {
46+
data = append(data, blk.Seed...)
47+
}
48+
49+
if blk.Proof != nil {
50+
data = append(data, blk.Proof...)
51+
}
52+
53+
return common.Sha256(data)
3554
}
3655

3756
func (blk *Block) RecoverPubkey() *PublicKey {
@@ -62,14 +81,17 @@ func newBlockchain() *Blockchain {
6281
}
6382

6483
func (bc *Blockchain) init() {
84+
rand.Seed(time.Now().Unix())
6585
emptyHash := common.Sha256([]byte{})
6686
// create genesis
6787
bc.genesis = &Block{
6888
Round: 0,
89+
Seed: common.Uint2Bytes(rand.Uint64()),
6990
ParentHash: emptyHash,
7091
Author: common.HashToAddr(emptyHash),
7192
Time: time.Now().Unix(),
7293
}
94+
bc.last = bc.genesis
7395
}
7496

7597
func (bc *Blockchain) get(hash common.Hash, round uint64) *Block {
@@ -86,14 +108,14 @@ func (bc *Blockchain) getByRound(round uint64) *Block {
86108
bc.mu.RLock()
87109
defer bc.mu.RUnlock()
88110
last := bc.last
89-
for round != 0 {
111+
for round > 0 {
90112
if last.Round == round {
91113
return last
92114
}
93115
last = bc.blocks[round-1][last.ParentHash]
94116
round--
95117
}
96-
return nil
118+
return last
97119
}
98120

99121
func (bc *Blockchain) add(blk *Block) {

common/config.go

-6
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,6 @@ import (
77
"time"
88
)
99

10-
const (
11-
MAX_GAS_LIMIT = "max_gas_limit"
12-
MAX_EXTRA_LENGTH = "max_extra_length"
13-
MAX_BLOCK_NUM = "max_block_num"
14-
)
15-
1610
type Config struct {
1711
conf *viper.Viper
1812
mu sync.RWMutex

common/types.go

-14
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import (
55
"crypto/sha256"
66
"encoding/binary"
77
"encoding/hex"
8-
"github.com/libp2p/go-libp2p-peer"
9-
"github.com/tinychain/tinychain/p2p/pb"
108
"math/big"
119
)
1210

@@ -123,18 +121,6 @@ func HexToAddress(d string) Address {
123121
return BytesToAddress(dec)
124122
}
125123

126-
// Protocol represents the callback handler
127-
type Protocol interface {
128-
// Typ should match the message type
129-
Type() string
130-
131-
// Run func handles the message from the stream
132-
Run(pid peer.ID, message *pb.Message) error
133-
134-
// Error func handles the error returned from the stream
135-
Error(error)
136-
}
137-
138124
func Uint2Bytes(v uint64) []byte {
139125
b := make([]byte, 8)
140126
binary.BigEndian.PutUint64(b, v)

crypto.go

+9-7
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@ import (
55
"crypto/rand"
66
"fmt"
77
"github.com/tinychain/algorand/common"
8+
"github.com/tinychain/algorand/vrf"
89
"golang.org/x/crypto/ed25519"
9-
rander "math/rand"
10-
"time"
1110
)
1211

1312
type PublicKey struct {
@@ -30,7 +29,8 @@ func (pub *PublicKey) VerifySign(m, sign []byte) error {
3029
return nil
3130
}
3231

33-
func (pub *PublicKey) VerifyVRF(vrf, proof, m []byte) error {
32+
func (pub *PublicKey) VerifyVRF(proof, m []byte) error {
33+
vrf.ECVRF_verify(pub.pk, proof, m)
3434
return nil
3535
}
3636

@@ -51,10 +51,12 @@ func (priv *PrivateKey) Sign(m []byte) ([]byte, error) {
5151
return append(pubkey, sign...), nil
5252
}
5353

54-
func (priv *PrivateKey) Evaluate(m []byte) (value, proof []byte) {
55-
rander.Seed(time.Now().UnixNano())
56-
value, proof = common.Sha256(common.Uint2Bytes(rander.Uint64())).Bytes(),
57-
common.Sha256(common.Uint2Bytes(rander.Uint64())).Bytes()
54+
func (priv *PrivateKey) Evaluate(m []byte) (value, proof []byte, err error) {
55+
proof, err = vrf.ECVRF_prove(priv.PublicKey().pk, priv.sk, m)
56+
if err != nil {
57+
return
58+
}
59+
value = vrf.ECVRF_proof2hash(proof)
5860
return
5961
}
6062

0 commit comments

Comments
 (0)