diff --git a/keys/ecc.go b/keys/ecc.go index ba754d525..96590cd91 100644 --- a/keys/ecc.go +++ b/keys/ecc.go @@ -4,6 +4,7 @@ import ( "encoding/binary" "errors" "hash/crc32" + "hash/crc64" ) // ECC is used for anything that calculates an error-correcting code @@ -33,6 +34,18 @@ type CRC32 struct { var _ ECC = &CRC32{} +func NewIEEECRC32() *CRC32 { + return &CRC32{Poly: crc32.IEEE} +} + +func NewCastagnoliCRC32() *CRC32 { + return &CRC32{Poly: crc32.Castagnoli} +} + +func NewKoopmanCRC32() *CRC32 { + return &CRC32{Poly: crc32.Koopman} +} + func (c *CRC32) AddECC(input []byte) []byte { table := c.getTable() @@ -71,3 +84,58 @@ func (c *CRC32) getTable() *crc32.Table { } return c.table } + +// CRC64 does the ieee crc64 polynomial check +type CRC64 struct { + Poly uint64 + table *crc64.Table +} + +var _ ECC = &CRC64{} + +func NewISOCRC64() *CRC64 { + return &CRC64{Poly: crc64.ISO} +} + +func NewECMACRC64() *CRC64 { + return &CRC64{Poly: crc64.ECMA} +} + +func (c *CRC64) AddECC(input []byte) []byte { + table := c.getTable() + + // get crc and convert to some bytes... + crc := crc64.Checksum(input, table) + check := make([]byte, crc64.Size) + binary.BigEndian.PutUint64(check, crc) + + // append it to the input + output := append(input, check...) + return output +} + +func (c *CRC64) CheckECC(input []byte) ([]byte, error) { + table := c.getTable() + + if len(input) <= crc64.Size { + return nil, errors.New("input too short, no checksum present") + } + cut := len(input) - crc64.Size + data, check := input[:cut], input[cut:] + crc := binary.BigEndian.Uint64(check) + calc := crc64.Checksum(data, table) + if crc != calc { + return nil, errors.New("Checksum does not match") + } + return data, nil +} + +func (c *CRC64) getTable() *crc64.Table { + if c.table == nil { + if c.Poly == 0 { + c.Poly = crc64.ISO + } + c.table = crc64.MakeTable(c.Poly) + } + return c.table +} diff --git a/keys/ecc_test.go b/keys/ecc_test.go index a85d4ddd7..334c49423 100644 --- a/keys/ecc_test.go +++ b/keys/ecc_test.go @@ -1,7 +1,6 @@ package keys import ( - "hash/crc32" "testing" "github.com/stretchr/testify/assert" @@ -13,7 +12,14 @@ import ( func TestECCPasses(t *testing.T) { assert := assert.New(t) - checks := []ECC{NoECC{}, &CRC32{}, &CRC32{Poly: crc32.Castagnoli}} + checks := []ECC{ + NoECC{}, + NewIEEECRC32(), + NewCastagnoliCRC32(), + NewKoopmanCRC32(), + NewISOCRC64(), + NewECMACRC64(), + } for _, check := range checks { for i := 0; i < 2000; i++ { @@ -22,7 +28,7 @@ func TestECCPasses(t *testing.T) { checked := check.AddECC(data) res, err := check.CheckECC(checked) - if assert.Nil(err, "%v: %+v", check, err) { + if assert.Nil(err, "%#v: %+v", check, err) { assert.Equal(data, res, "%v", check) } } @@ -33,7 +39,13 @@ func TestECCPasses(t *testing.T) { func TestECCFails(t *testing.T) { assert := assert.New(t) - checks := []ECC{&CRC32{}, &CRC32{Poly: crc32.Castagnoli}} + checks := []ECC{ + NewIEEECRC32(), + NewCastagnoliCRC32(), + NewKoopmanCRC32(), + NewISOCRC64(), + NewECMACRC64(), + } attempts := 2000