Skip to content

Commit

Permalink
Add validation of the ValidatorsHash, Round and Proof (#510)
Browse files Browse the repository at this point in the history
* Add ProofLength to vrf interface

* Add validation of the ValidatorsHash, Round and Proof

* Add test case of the ValidatorsHash, Round and Proof

* Fix makeRandHeader to generate rand proof

* Make libsodium compatible with M1 Mac

* Fix to run test with correct Header.Proof

* Resolve e2e test failure due to build tag diff

* Change ProofLength() to const ProofSize

* Separate the diff with tendermint down into the code

* Change e2e test build from libsodium to r2ishiguro

* Revert e2e test build and Change runner build from default to libsodium

* Fix e2e test actions bug

* Add build tag option to test proccess

* Use ProofSize from coniks

* Remove unnecessary upload
  • Loading branch information
Mdaiki0730 authored Nov 30, 2022
1 parent 71df846 commit 07a894b
Show file tree
Hide file tree
Showing 13 changed files with 70 additions and 17 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ jobs:
docker load -i ${{ needs.e2e-build.outputs.CACHE_FILE }}
if: "env.GIT_DIFF != ''"

- name: Build libsodium
run: make libsodium

- name: Build e2e runner
working-directory: test/e2e
run: make runner
Expand Down
3 changes: 3 additions & 0 deletions crypto/vrf/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,20 @@ Use `func init()` with `build` option
* `//go:build libsodium`
* `// +build !libsodium,!coniks`
* `func init() { defaultVrf = newVrfEd25519r2ishiguro() }`
* `const ProofSize = 81`
* vrf_r2ishiguro.go
* (coniks)
* `//go:build coniks`
* `// +build coniks`
* `func init() { defaultVrf = newVrfEd25519coniks() }`
* `const ProofSize = 96`
* vrf_coniks.go
* vrf_coniks_test.go
* (libsodium)
* `//go:build libsodium`
* `// +build libsodium`
* `func init() { defaultVrf = newVrfEd25519libsodium() }`
* `const ProofSize = int(libsodium.PROOFBYTES)`
* vrf_libsodium.go
* vrf_libsodium_test.go

Expand Down
2 changes: 2 additions & 0 deletions crypto/vrf/internal/vrf/vrf.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ package vrf
#cgo CFLAGS: -Wall -std=c99
#cgo darwin,amd64 CFLAGS: -I./sodium/darwin_amd64/include/
#cgo darwin,amd64 LDFLAGS: -L./sodium/darwin_amd64/lib -lsodium
#cgo darwin,arm64 CFLAGS: -I./sodium/darwin_arm64/include/
#cgo darwin,arm64 LDFLAGS: -L./sodium/darwin_arm64/lib -lsodium
#cgo linux,amd64 CFLAGS: -I./sodium/linux_amd64/include
#cgo linux,amd64 LDFLAGS: -L./sodium/linux_amd64/lib -lsodium
#cgo linux,arm64 CFLAGS: -I./sodium/linux_arm64/include
Expand Down
2 changes: 2 additions & 0 deletions crypto/vrf/vrf_coniks.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ func init() {
defaultVrf = newVrfEd25519coniks()
}

const ProofSize = coniks.ProofSize

func newVrfEd25519coniks() *vrfEd25519coniks {
return &vrfEd25519coniks{nil, nil}
}
Expand Down
2 changes: 2 additions & 0 deletions crypto/vrf/vrf_libsodium.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ func init() {
defaultVrf = newVrfEd25519libsodium()
}

const ProofSize = int(libsodium.PROOFBYTES)

func newVrfEd25519libsodium() vrfEd25519libsodium {
return vrfEd25519libsodium{}
}
Expand Down
2 changes: 2 additions & 0 deletions crypto/vrf/vrf_r2ishiguro.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ func init() {
}
}

const ProofSize = 81

func newVrfEd25519r2ishiguro() vrfEd25519r2ishiguro {
return vrfEd25519r2ishiguro{}
}
Expand Down
13 changes: 7 additions & 6 deletions evidence/pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"testing"
"time"

"github.com/line/ostracon/crypto"
"github.com/line/ostracon/crypto/bls"
"github.com/line/ostracon/crypto/composite"
"github.com/line/ostracon/crypto/ed25519"
Expand Down Expand Up @@ -325,12 +326,11 @@ func TestLightClientAttackEvidenceLifecycle(t *testing.T) {
func TestRecoverPendingEvidence(t *testing.T) {
height := int64(10)
val := types.NewMockPV(types.PrivKeyComposite) // TODO 🏺 need to test by all key types
valAddress := val.PrivKey.PubKey().Address()
evidenceDB := dbm.NewMemDB()
stateStore := initializeValidatorState(val, height)
state, err := stateStore.Load()
require.NoError(t, err)
blockStore := initializeBlockStore(dbm.NewMemDB(), state, valAddress)
blockStore := initializeBlockStore(dbm.NewMemDB(), state, val.PrivKey)
// create previous pool and populate it
pool, err := evidence.NewPool(evidenceDB, stateStore, blockStore)
require.NoError(t, err)
Expand Down Expand Up @@ -424,13 +424,15 @@ func initializeValidatorState(privVal types.PrivValidator, height int64) sm.Stor

// initializeBlockStore creates a block storage and populates it w/ a dummy
// block at +height+.
func initializeBlockStore(db dbm.DB, state sm.State, valAddr []byte) *store.BlockStore {
func initializeBlockStore(db dbm.DB, state sm.State, valPrivkey crypto.PrivKey) *store.BlockStore {
blockStore := store.NewBlockStore(db)
valAddr := valPrivkey.PubKey().Address()

for i := int64(1); i <= state.LastBlockHeight; i++ {
round := int32(0)
lastCommit := makeCommit(i-1, valAddr)
proof := state.MakeHashMessage(round)
message := state.MakeHashMessage(round)
proof, _ := valPrivkey.VRFProve(message)
block, _ := state.MakeBlock(i, []types.Tx{}, lastCommit, nil,
state.Validators.SelectProposer(proof, i, round).Address, round, proof)
block.Header.Time = defaultEvidenceTime.Add(time.Duration(i) * time.Minute)
Expand All @@ -457,11 +459,10 @@ func makeCommit(height int64, valAddr []byte) *types.Commit {

func defaultTestPool(height int64) (*evidence.Pool, types.MockPV) {
val := types.NewMockPV(types.PrivKeyComposite) // TODO 🏺 need to test by all key types
valAddress := val.PrivKey.PubKey().Address()
evidenceDB := dbm.NewMemDB()
stateStore := initializeValidatorState(val, height)
state, _ := stateStore.Load()
blockStore := initializeBlockStore(dbm.NewMemDB(), state, valAddress)
blockStore := initializeBlockStore(dbm.NewMemDB(), state, val.PrivKey)
pool, err := evidence.NewPool(evidenceDB, stateStore, blockStore)
if err != nil {
panic("test evidence pool could not be created")
Expand Down
3 changes: 1 addition & 2 deletions evidence/verify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@ import (

"github.com/line/ostracon/light"

"github.com/coniks-sys/coniks-go/crypto/vrf"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

dbm "github.com/tendermint/tm-db"

"github.com/line/ostracon/crypto"
"github.com/line/ostracon/crypto/tmhash"
"github.com/line/ostracon/crypto/vrf"
"github.com/line/ostracon/evidence"
"github.com/line/ostracon/evidence/mocks"
"github.com/line/ostracon/libs/log"
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ maverick:
go build -o build/maverick -tags libsodium,badgerdb,boltdb,cleveldb,rocksdb ../maverick

generator:
go build -o build/generator ./generator
go build -o build/generator -tags libsodium ./generator

runner:
go build -o build/runner ./runner
go build -o build/runner -tags libsodium ./runner

.PHONY: all node docker generator maverick runner
2 changes: 1 addition & 1 deletion test/e2e/runner/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ func Test(testnet *e2e.Testnet) error {
return err
}

return execVerbose("go", "test", "-count", "1", "./tests/...")
return execVerbose("go", "test", "-count", "1", "-tags", "libsodium", "./tests/...")
}
17 changes: 14 additions & 3 deletions types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -455,10 +455,9 @@ func (h Header) ValidateBasic() error {

// Basic validation of hashes related to application data.
// Will validate fully against state in state#ValidateBlock.
if err := ValidateHash(h.VotersHash); err != nil {
return fmt.Errorf("wrong VotersHash: %v", err)
if err := ValidateHash(h.ValidatorsHash); err != nil {
return fmt.Errorf("wrong ValidatorsHash: %v", err)
}
// TODO When we add `Header.ValidatorsHash` in a future commit, we have to add a similar check here.
if err := ValidateHash(h.NextValidatorsHash); err != nil {
return fmt.Errorf("wrong NextValidatorsHash: %v", err)
}
Expand All @@ -470,6 +469,18 @@ func (h Header) ValidateBasic() error {
return fmt.Errorf("wrong LastResultsHash: %v", err)
}

if err := ValidateHash(h.VotersHash); err != nil {
return fmt.Errorf("wrong VotersHash: %v", err)
}

if h.Round < 0 {
return errors.New("negative Round")
}

if err := ValidateProof(h.Proof); err != nil {
return fmt.Errorf("wrong Proof: %v", err)
}

return nil
}

Expand Down
21 changes: 18 additions & 3 deletions types/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,9 @@ func TestHeaderHash(t *testing.T) {
EvidenceHash: tmhash.Sum([]byte("evidence_hash")),
ProposerAddress: crypto.AddressHash([]byte("proposer_address")),
Round: 1,
Proof: tmhash.Sum([]byte("proof")),
// The Proof defined here does not depend on the vrf ProofLength,
// but it is a fixed value for the purpose of calculating the Hash value.
Proof: tmhash.Sum([]byte("proof")),
}, hexBytesFromString("0368E6F15B6B7BC9DC5B10F36F37D6F867E132A22333F083A11290324274E183")},
{"nil header yields nil", nil, nil},
{"nil VotersHash yields nil", &Header{
Expand All @@ -537,7 +539,9 @@ func TestHeaderHash(t *testing.T) {
EvidenceHash: tmhash.Sum([]byte("evidence_hash")),
ProposerAddress: crypto.AddressHash([]byte("proposer_address")),
Round: 1,
Proof: tmhash.Sum([]byte("proof")),
// The Proof defined here does not depend on the vrf ProofLength,
// but it is a fixed value for the purpose of calculating the Hash value.
Proof: tmhash.Sum([]byte("proof")),
}, nil},
}
for _, tc := range testCases {
Expand Down Expand Up @@ -638,6 +642,15 @@ func TestHeaderValidateBasic(t *testing.T) {
{"Invalid Results Hash", func(header *Header) {
header.LastResultsHash = []byte(strings.Repeat("h", invalidHashLength))
}, true},
{"Negative Round", func(header *Header) {
header.Round = -1
}, true},
{"Invalid Proof", func(header *Header) {
header.Proof = make([]byte, vrf.ProofSize-1)
}, true},
{"Invalid Validators Hash", func(header *Header) {
header.ValidatorsHash = []byte(strings.Repeat("h", invalidHashLength))
}, true},
}
for i, tc := range testCases {
tc := tc
Expand All @@ -660,7 +673,7 @@ func TestHeaderValidateBasic(t *testing.T) {
EvidenceHash: tmhash.Sum([]byte("evidence_hash")),
ProposerAddress: crypto.AddressHash([]byte("proposer_address")),
Round: 1,
Proof: tmhash.Sum([]byte("proof")),
Proof: make([]byte, vrf.ProofSize),
}
tc.malleateHeader(header)
err := header.ValidateBasic()
Expand Down Expand Up @@ -1268,6 +1281,7 @@ func makeRandHeader() Header {
height := tmrand.Int63()
randBytes := tmrand.Bytes(tmhash.Size)
randAddress := tmrand.Bytes(crypto.AddressSize)
randProof := tmrand.Bytes(vrf.ProofSize)
h := Header{
Version: tmversion.Consensus{Block: version.BlockProtocol, App: 1},
ChainID: chainID,
Expand All @@ -1285,6 +1299,7 @@ func makeRandHeader() Header {

EvidenceHash: randBytes,
ProposerAddress: randAddress,
Proof: randProof,
}

return h
Expand Down
13 changes: 13 additions & 0 deletions types/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"time"

"github.com/line/ostracon/crypto/tmhash"
"github.com/line/ostracon/crypto/vrf"
tmtime "github.com/line/ostracon/types/time"
)

Expand Down Expand Up @@ -38,3 +39,15 @@ func ValidateHash(h []byte) error {
}
return nil
}

// ValidateProof returns an error if the proof is not empty, but its
// size != vrf.ProofSize.
func ValidateProof(h []byte) error {
if len(h) > 0 && len(h) != vrf.ProofSize {
return fmt.Errorf("expected size to be %d bytes, got %d bytes",
vrf.ProofSize,
len(h),
)
}
return nil
}

0 comments on commit 07a894b

Please sign in to comment.