Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add validation of the ValidatorsHash, Round and Proof #510

Merged
merged 15 commits into from
Nov 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)`
ulbqb marked this conversation as resolved.
Show resolved Hide resolved
* 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)
ulbqb marked this conversation as resolved.
Show resolved Hide resolved

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
}