mirror of
https://github.com/tendermint/tendermint.git
synced 2026-08-29 04:07:07 +00:00
Add first pass of ecc checksuming
This commit is contained in:
+56
@@ -0,0 +1,56 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"hash/crc32"
|
||||
)
|
||||
|
||||
// ECC is used for anything that calculates an error-correcting code
|
||||
type ECC interface {
|
||||
// AddECC calculates an error-correcting code for the input
|
||||
// returns an output with the code appended
|
||||
AddECC([]byte) []byte
|
||||
|
||||
// CheckECC verifies if the ECC is proper on the input and returns
|
||||
// the data with the code removed, or an error
|
||||
CheckECC([]byte) ([]byte, error)
|
||||
}
|
||||
|
||||
// NoECC is a no-op placeholder, kind of useless... except for tests
|
||||
type NoECC struct{}
|
||||
|
||||
var _ ECC = NoECC{}
|
||||
|
||||
func (_ NoECC) AddECC(input []byte) []byte { return input }
|
||||
func (_ NoECC) CheckECC(input []byte) ([]byte, error) { return input, nil }
|
||||
|
||||
// CRC32 does the ieee crc32 polynomial check
|
||||
type CRC32 struct{}
|
||||
|
||||
var _ ECC = CRC32{}
|
||||
|
||||
func (_ CRC32) AddECC(input []byte) []byte {
|
||||
// get crc and convert to some bytes...
|
||||
crc := crc32.ChecksumIEEE(input)
|
||||
check := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(check, crc)
|
||||
|
||||
// append it to the input
|
||||
output := append(input, check...)
|
||||
return output
|
||||
}
|
||||
|
||||
func (_ CRC32) CheckECC(input []byte) ([]byte, error) {
|
||||
if len(input) <= 4 {
|
||||
return nil, errors.New("input too short, no checksum present")
|
||||
}
|
||||
cut := len(input) - 4
|
||||
data, check := input[:cut], input[cut:]
|
||||
crc := binary.BigEndian.Uint32(check)
|
||||
calc := crc32.ChecksumIEEE(data)
|
||||
if crc != calc {
|
||||
return nil, errors.New("Checksum does not match")
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
)
|
||||
|
||||
// TestECCPasses makes sure that the AddECC/CheckECC methods are symetric
|
||||
func TestECCPasses(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
checks := []ECC{NoECC{}, CRC32{}}
|
||||
|
||||
for _, check := range checks {
|
||||
for i := 0; i < 2000; i++ {
|
||||
numBytes := cmn.RandInt()%60 + 1
|
||||
data := cmn.RandBytes(numBytes)
|
||||
|
||||
checked := check.AddECC(data)
|
||||
res, err := check.CheckECC(checked)
|
||||
if assert.Nil(err, "%v: %+v", check, err) {
|
||||
assert.Equal(data, res, "%v", check)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestECCFails makes sure random data will (usually) fail the checksum
|
||||
func TestECCFails(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
checks := []ECC{CRC32{}}
|
||||
|
||||
attempts := 2000
|
||||
|
||||
for _, check := range checks {
|
||||
failed := 0
|
||||
for i := 0; i < attempts; i++ {
|
||||
numBytes := cmn.RandInt()%60 + 1
|
||||
data := cmn.RandBytes(numBytes)
|
||||
_, err := check.CheckECC(data)
|
||||
if err != nil {
|
||||
failed += 1
|
||||
}
|
||||
}
|
||||
// we allow up to 1 falsely accepted checksums, as there are random matches
|
||||
assert.InDelta(attempts, failed, 1, "%v", check)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user