Browse Source

TMHASH is 32 bytes. Closes #1990 (#2732)

* tmhash is fully 32 bytes. closes #1990

* AddressSize

* fix tests

* fix max sizes
pull/2746/head
Ethan Buchman 6 years ago
committed by GitHub
parent
commit
a22c962e28
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 96 additions and 51 deletions
  1. +15
    -6
      crypto/crypto.go
  2. +1
    -1
      crypto/ed25519/ed25519.go
  3. +6
    -6
      crypto/merkle/simple_map_test.go
  4. +25
    -8
      crypto/tmhash/hash.go
  5. +21
    -2
      crypto/tmhash/hash_test.go
  6. +1
    -1
      docs/spec/blockchain/blockchain.md
  7. +3
    -4
      docs/spec/blockchain/encoding.md
  8. +2
    -2
      docs/spec/blockchain/state.md
  9. +1
    -2
      p2p/key.go
  10. +2
    -2
      state/validation.go
  11. +1
    -1
      types/block.go
  12. +9
    -8
      types/block_test.go
  13. +1
    -1
      types/evidence.go
  14. +4
    -4
      types/validator.go
  15. +1
    -1
      types/vote.go
  16. +3
    -2
      types/vote_test.go

+ 15
- 6
crypto/crypto.go View File

@ -1,21 +1,23 @@
package crypto
import (
"github.com/tendermint/tendermint/crypto/tmhash"
cmn "github.com/tendermint/tendermint/libs/common"
)
type PrivKey interface {
Bytes() []byte
Sign(msg []byte) ([]byte, error)
PubKey() PubKey
Equals(PrivKey) bool
}
const (
AddressSize = tmhash.TruncatedSize
)
// An address is a []byte, but hex-encoded even in JSON.
// []byte leaves us the option to change the address length.
// Use an alias so Unmarshal methods (with ptr receivers) are available too.
type Address = cmn.HexBytes
func AddressHash(bz []byte) Address {
return Address(tmhash.SumTruncated(bz))
}
type PubKey interface {
Address() Address
Bytes() []byte
@ -23,6 +25,13 @@ type PubKey interface {
Equals(PubKey) bool
}
type PrivKey interface {
Bytes() []byte
Sign(msg []byte) ([]byte, error)
PubKey() PubKey
Equals(PrivKey) bool
}
type Symmetric interface {
Keygen() []byte
Encrypt(plaintext []byte, secret []byte) (ciphertext []byte)


+ 1
- 1
crypto/ed25519/ed25519.go View File

@ -136,7 +136,7 @@ type PubKeyEd25519 [PubKeyEd25519Size]byte
// Address is the SHA256-20 of the raw pubkey bytes.
func (pubKey PubKeyEd25519) Address() crypto.Address {
return crypto.Address(tmhash.Sum(pubKey[:]))
return crypto.Address(tmhash.SumTruncated(pubKey[:]))
}
// Bytes marshals the PubKey using amino encoding.


+ 6
- 6
crypto/merkle/simple_map_test.go View File

@ -13,14 +13,14 @@ func TestSimpleMap(t *testing.T) {
values []string // each string gets converted to []byte in test
want string
}{
{[]string{"key1"}, []string{"value1"}, "fa9bc106ffd932d919bee935ceb6cf2b3dd72d8f"},
{[]string{"key1"}, []string{"value2"}, "e00e7dcfe54e9fafef5111e813a587f01ba9c3e8"},
{[]string{"key1"}, []string{"value1"}, "321d150de16dceb51c72981b432b115045383259b1a550adf8dc80f927508967"},
{[]string{"key1"}, []string{"value2"}, "2a9e4baf321eac99f6eecc3406603c14bc5e85bb7b80483cbfc75b3382d24a2f"},
// swap order with 2 keys
{[]string{"key1", "key2"}, []string{"value1", "value2"}, "eff12d1c703a1022ab509287c0f196130123d786"},
{[]string{"key2", "key1"}, []string{"value2", "value1"}, "eff12d1c703a1022ab509287c0f196130123d786"},
{[]string{"key1", "key2"}, []string{"value1", "value2"}, "c4d8913ab543ba26aa970646d4c99a150fd641298e3367cf68ca45fb45a49881"},
{[]string{"key2", "key1"}, []string{"value2", "value1"}, "c4d8913ab543ba26aa970646d4c99a150fd641298e3367cf68ca45fb45a49881"},
// swap order with 3 keys
{[]string{"key1", "key2", "key3"}, []string{"value1", "value2", "value3"}, "b2c62a277c08dbd2ad73ca53cd1d6bfdf5830d26"},
{[]string{"key1", "key3", "key2"}, []string{"value1", "value3", "value2"}, "b2c62a277c08dbd2ad73ca53cd1d6bfdf5830d26"},
{[]string{"key1", "key2", "key3"}, []string{"value1", "value2", "value3"}, "b23cef00eda5af4548a213a43793f2752d8d9013b3f2b64bc0523a4791196268"},
{[]string{"key1", "key3", "key2"}, []string{"value1", "value3", "value2"}, "b23cef00eda5af4548a213a43793f2752d8d9013b3f2b64bc0523a4791196268"},
}
for i, tc := range tests {
db := newSimpleMap()


+ 25
- 8
crypto/tmhash/hash.go View File

@ -6,10 +6,27 @@ import (
)
const (
Size = 20
Size = sha256.Size
BlockSize = sha256.BlockSize
)
// New returns a new hash.Hash.
func New() hash.Hash {
return sha256.New()
}
// Sum returns the SHA256 of the bz.
func Sum(bz []byte) []byte {
h := sha256.Sum256(bz)
return h[:]
}
//-------------------------------------------------------------
const (
TruncatedSize = 20
)
type sha256trunc struct {
sha256 hash.Hash
}
@ -19,7 +36,7 @@ func (h sha256trunc) Write(p []byte) (n int, err error) {
}
func (h sha256trunc) Sum(b []byte) []byte {
shasum := h.sha256.Sum(b)
return shasum[:Size]
return shasum[:TruncatedSize]
}
func (h sha256trunc) Reset() {
@ -27,22 +44,22 @@ func (h sha256trunc) Reset() {
}
func (h sha256trunc) Size() int {
return Size
return TruncatedSize
}
func (h sha256trunc) BlockSize() int {
return h.sha256.BlockSize()
}
// New returns a new hash.Hash.
func New() hash.Hash {
// NewTruncated returns a new hash.Hash.
func NewTruncated() hash.Hash {
return sha256trunc{
sha256: sha256.New(),
}
}
// Sum returns the first 20 bytes of SHA256 of the bz.
func Sum(bz []byte) []byte {
// SumTruncated returns the first 20 bytes of SHA256 of the bz.
func SumTruncated(bz []byte) []byte {
hash := sha256.Sum256(bz)
return hash[:Size]
return hash[:TruncatedSize]
}

+ 21
- 2
crypto/tmhash/hash_test.go View File

@ -14,10 +14,29 @@ func TestHash(t *testing.T) {
hasher.Write(testVector)
bz := hasher.Sum(nil)
bz2 := tmhash.Sum(testVector)
hasher = sha256.New()
hasher.Write(testVector)
bz3 := hasher.Sum(nil)
assert.Equal(t, bz, bz2)
assert.Equal(t, bz, bz3)
}
func TestHashTruncated(t *testing.T) {
testVector := []byte("abc")
hasher := tmhash.NewTruncated()
hasher.Write(testVector)
bz := hasher.Sum(nil)
bz2 := tmhash.SumTruncated(testVector)
hasher = sha256.New()
hasher.Write(testVector)
bz2 := hasher.Sum(nil)
bz2 = bz2[:20]
bz3 := hasher.Sum(nil)
bz3 = bz3[:tmhash.TruncatedSize]
assert.Equal(t, bz, bz2)
assert.Equal(t, bz, bz3)
}

+ 1
- 1
docs/spec/blockchain/blockchain.md View File

@ -344,7 +344,7 @@ next validator sets Merkle root.
### ConsensusParamsHash
```go
block.ConsensusParamsHash == tmhash(amino(state.ConsensusParams))
block.ConsensusParamsHash == TMHASH(amino(state.ConsensusParams))
```
Hash of the amino-encoded consensus parameters.


+ 3
- 4
docs/spec/blockchain/encoding.md View File

@ -176,13 +176,12 @@ greater, for example:
h0 h1 h3 h4 h0 h1 h2 h3 h4 h5
```
Tendermint always uses the `TMHASH` hash function, which is the first 20-bytes
of the SHA256:
Tendermint always uses the `TMHASH` hash function, which is equivalent to
SHA256:
```
func TMHASH(bz []byte) []byte {
shasum := SHA256(bz)
return shasum[:20]
return SHA256(bz)
}
```


+ 2
- 2
docs/spec/blockchain/state.md View File

@ -56,8 +56,8 @@ type Validator struct {
}
```
When hashing the Validator struct, the pubkey is not hashed,
because the address is already the hash of the pubkey.
When hashing the Validator struct, the address is not included,
because it is redundant with the pubkey.
The `state.Validators`, `state.LastValidators`, and `state.NextValidators`, must always by sorted by validator address,
so that there is a canonical order for computing the SimpleMerkleRoot.


+ 1
- 2
p2p/key.go View File

@ -8,7 +8,6 @@ import (
crypto "github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/tendermint/tendermint/crypto/tmhash"
cmn "github.com/tendermint/tendermint/libs/common"
)
@ -17,7 +16,7 @@ type ID string
// IDByteLength is the length of a crypto.Address. Currently only 20.
// TODO: support other length addresses ?
const IDByteLength = tmhash.Size
const IDByteLength = crypto.AddressSize
//------------------------------------------------------------------------------
// Persistent peer ID


+ 2
- 2
state/validation.go View File

@ -5,7 +5,7 @@ import (
"errors"
"fmt"
"github.com/tendermint/tendermint/crypto/tmhash"
"github.com/tendermint/tendermint/crypto"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/types"
)
@ -158,7 +158,7 @@ func validateBlock(stateDB dbm.DB, state State, block *types.Block) error {
// NOTE: We can't actually verify it's the right proposer because we dont
// know what round the block was first proposed. So just check that it's
// a legit address and a known validator.
if len(block.ProposerAddress) != tmhash.Size ||
if len(block.ProposerAddress) != crypto.AddressSize ||
!state.Validators.HasAddress(block.ProposerAddress) {
return fmt.Errorf(
"Block.Header.ProposerAddress, %X, is not a validator",


+ 1
- 1
types/block.go View File

@ -15,7 +15,7 @@ import (
const (
// MaxHeaderBytes is a maximum header size (including amino overhead).
MaxHeaderBytes int64 = 533
MaxHeaderBytes int64 = 653
// MaxAminoOverheadForBlock - maximum amino overhead to encode a block (up to
// MaxBlockSizeBytes in size) not including it's parts except Data.


+ 9
- 8
types/block_test.go View File

@ -10,6 +10,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/tmhash"
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/version"
@ -116,7 +117,7 @@ func TestBlockMakePartSetWithEvidence(t *testing.T) {
partSet := MakeBlock(h, []Tx{Tx("Hello World")}, commit, evList).MakePartSet(1024)
assert.NotNil(t, partSet)
assert.Equal(t, 2, partSet.Total())
assert.Equal(t, 3, partSet.Total())
}
func TestBlockHashesTo(t *testing.T) {
@ -262,7 +263,7 @@ func TestMaxHeaderBytes(t *testing.T) {
AppHash: tmhash.Sum([]byte("app_hash")),
LastResultsHash: tmhash.Sum([]byte("last_results_hash")),
EvidenceHash: tmhash.Sum([]byte("evidence_hash")),
ProposerAddress: tmhash.Sum([]byte("proposer_address")),
ProposerAddress: crypto.AddressHash([]byte("proposer_address")),
}
bz, err := cdc.MarshalBinaryLengthPrefixed(h)
@ -292,9 +293,9 @@ func TestBlockMaxDataBytes(t *testing.T) {
}{
0: {-10, 1, 0, true, 0},
1: {10, 1, 0, true, 0},
2: {742, 1, 0, true, 0},
3: {743, 1, 0, false, 0},
4: {744, 1, 0, false, 1},
2: {886, 1, 0, true, 0},
3: {887, 1, 0, false, 0},
4: {888, 1, 0, false, 1},
}
for i, tc := range testCases {
@ -320,9 +321,9 @@ func TestBlockMaxDataBytesUnknownEvidence(t *testing.T) {
}{
0: {-10, 1, true, 0},
1: {10, 1, true, 0},
2: {824, 1, true, 0},
3: {825, 1, false, 0},
4: {826, 1, false, 1},
2: {984, 1, true, 0},
3: {985, 1, false, 0},
4: {986, 1, false, 1},
}
for i, tc := range testCases {


+ 1
- 1
types/evidence.go View File

@ -14,7 +14,7 @@ import (
const (
// MaxEvidenceBytes is a maximum size of any evidence (including amino overhead).
MaxEvidenceBytes int64 = 436
MaxEvidenceBytes int64 = 484
)
// ErrEvidenceInvalid wraps a piece of evidence and the error denoting how or why it is invalid.


+ 4
- 4
types/validator.go View File

@ -77,15 +77,15 @@ func (v *Validator) Hash() []byte {
}
// Bytes computes the unique encoding of a validator with a given voting power.
// These are the bytes that gets hashed in consensus. It excludes pubkey
// as its redundant with the address. This also excludes accum which changes
// These are the bytes that gets hashed in consensus. It excludes address
// as its redundant with the pubkey. This also excludes accum which changes
// every round.
func (v *Validator) Bytes() []byte {
return cdcEncode((struct {
Address Address
PubKey crypto.PubKey
VotingPower int64
}{
v.Address,
v.PubKey,
v.VotingPower,
}))
}


+ 1
- 1
types/vote.go View File

@ -12,7 +12,7 @@ import (
const (
// MaxVoteBytes is a maximum vote size (including amino overhead).
MaxVoteBytes int64 = 199
MaxVoteBytes int64 = 223
)
var (


+ 3
- 2
types/vote_test.go View File

@ -7,6 +7,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/tendermint/tendermint/crypto/tmhash"
)
@ -37,7 +38,7 @@ func exampleVote(t byte) *Vote {
Hash: tmhash.Sum([]byte("blockID_part_set_header_hash")),
},
},
ValidatorAddress: tmhash.Sum([]byte("validator_address")),
ValidatorAddress: crypto.AddressHash([]byte("validator_address")),
ValidatorIndex: 56789,
}
}
@ -211,7 +212,7 @@ func TestMaxVoteBytes(t *testing.T) {
timestamp := time.Date(math.MaxInt64, 0, 0, 0, 0, 0, math.MaxInt64, time.UTC)
vote := &Vote{
ValidatorAddress: tmhash.Sum([]byte("validator_address")),
ValidatorAddress: crypto.AddressHash([]byte("validator_address")),
ValidatorIndex: math.MaxInt64,
Height: math.MaxInt64,
Round: math.MaxInt64,


Loading…
Cancel
Save