├── LICENSE ├── README.md ├── crc.go └── crc_test.go /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, S&K Software Development Ltd 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the S&K Software Development Ltd nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | crc [![GoDoc](https://godoc.org/github.com/snksoft/src?status.png)](https://godoc.org/github.com/snksoft/crc) 2 | ======== 3 | This package implements generic CRC calculations up to 64 bits wide. 4 | It aims to be fairly fast and fairly complete, allowing users to match pretty much 5 | any CRC algorithm used in the wild by choosing appropriate Parameters. This obviously includes all popular CRC algorithms, such as CRC64-ISO, CRC64-ECMA, CRC32, CRC32C, CRC16, CCITT, XMODEM and many others. See http://reveng.sourceforge.net/crc-catalogue/ for a good list of CRC algorithms and their parameters. 6 | 7 | This package has been largely inspired by Ross Williams' 1993 paper "A Painless Guide to CRC Error Detection Algorithms". 8 | 9 | 10 | ## Installation 11 | 12 | To install, simply execute: 13 | 14 | ``` 15 | go get github.com/snksoft/crc 16 | ``` 17 | 18 | or: 19 | 20 | ``` 21 | go get gopkg.in/snksoft/crc.v1 22 | ``` 23 | 24 | ## Usage 25 | 26 | Using `crc` is easy. Here is an example of calculating a CCITT crc. 27 | ```go 28 | package main 29 | 30 | import ( 31 | "fmt" 32 | "github.com/snksoft/crc" 33 | ) 34 | 35 | func main() { 36 | data := "123456789" 37 | ccittCrc := crc.CalculateCRC(crc.CCITT, []byte(data)) 38 | fmt.Printf("CRC is 0x%04X\n", ccittCrc) // prints "CRC is 0x29B1" 39 | } 40 | ``` 41 | 42 | For larger data, table driven implementation is faster. Note that `crc.Hash` implements `hash.Hash` interface, so you can use it instead if you want. 43 | Here is how to use it: 44 | ```go 45 | package main 46 | 47 | import ( 48 | "fmt" 49 | "github.com/snksoft/crc" 50 | ) 51 | 52 | func main() { 53 | data := "123456789" 54 | hash := crc.NewHash(crc.XMODEM) 55 | xmodemCrc := hash.CalculateCRC([]byte(data)) 56 | fmt.Printf("CRC is 0x%04X\n", xmodemCrc) // prints "CRC is 0x31C3" 57 | 58 | // You can also reuse hash instance for another crc calculation 59 | // And if data is too big, you may feed it in chunks 60 | hash.Reset() // Discard crc data accumulated so far 61 | hash.Update([]byte("123456789")) // feed first chunk 62 | hash.Update([]byte("01234567890")) // feed next chunk 63 | xmodemCrc2 := hash.CRC() // gets CRC of whole data "12345678901234567890" 64 | fmt.Printf("CRC is 0x%04X\n", xmodemCrc2) // prints "CRC is 0x2C89" 65 | } 66 | ``` 67 | 68 | ## New in version 1.1 69 | 70 | In this version I have separated actual CRC caclulations and Hash interface implementation. New `Table` type incorporates table based implementation which can be used without creating a `Hash` instance. The main difference is that `Table` instances are essentially immutable once initialized. This greatly simplifies concurrent use as `Table` instances can be safely used in concurrent applications without tricky copying or synchronization. The downside is, however, that feeding data in multiple chunks becomes a bit more verbose (as you essentially maintain intermediate crc in your code and keep feeding it back to subsequent calls). So, you might prefer one or the other depending on situation at hand and personal preferences. You even can ask a `Hash` instance for a `Table` instance it uses internally and then use both in parallel without recalculating the crc table. 71 | 72 | Anyway, here is how to use a `Table` directly. 73 | 74 | ```go 75 | package main 76 | 77 | import ( 78 | "fmt" 79 | "github.com/snksoft/crc" 80 | ) 81 | 82 | func main() { 83 | data := []byte("123456789") 84 | 85 | // create a Table 86 | crcTable := crc.NewTable(crc.XMODEM) 87 | 88 | // Simple calculation all in one go 89 | xmodemCrc := crcTable.CalculateCRC(data) 90 | fmt.Printf("CRC is 0x%04X\n", xmodemCrc) // prints "CRC is 0x31C3" 91 | 92 | // You can also reuse same Table for another crc calculation 93 | // or even calculate multiple crc in parallel using same Table 94 | crc1 := crcTable.InitCrc() 95 | crc1 = crcTable.UpdateCrc(crc1, []byte("1234567890")) // feed first chunk to first crc 96 | crc2 := crcTable.InitCrc() 97 | crc2 = crcTable.UpdateCrc(crc2, data) // feed first chunk to second crc 98 | crc1 = crcTable.UpdateCrc(crc1, []byte("1234567890")) // feed second chunk to first crc 99 | 100 | // Now finish calcuation for both 101 | crc1 = crcTable.CRC(crc1) 102 | crc2 = crcTable.CRC(crc2) 103 | 104 | fmt.Printf("CRC is 0x%04X\n", crc1) // prints "CRC is 0x2C89" 105 | fmt.Printf("CRC is 0x%04X\n", crc2) // prints "CRC is 0x31C3" 106 | } 107 | ``` 108 | 109 | 110 | ## Notes 111 | Beware that `Hash` instance is not thread safe. If you want to do parallel CRC calculations (and actually need it to be `Hash`, not `Table`), then either use `NewHash()` to create multiple Hash instances or simply make a copy of Hash whehever you need it. Latter option avoids recalculating CRC table, but keep in mind that `NewHash()` returns a pointer, so simple assignement will point to the same instance. 112 | Use either 113 | ```go 114 | hash2 := &crc.Hash{} 115 | *hash2 = *hash 116 | ``` 117 | or simply 118 | ```go 119 | var hash2 = *hash 120 | ``` 121 | -------------------------------------------------------------------------------- /crc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016, S&K Software Development Ltd. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package crc implements generic CRC calculations up to 64 bits wide. 6 | // It aims to be fairly complete, allowing users to match pretty much 7 | // any CRC algorithm used in the wild by choosing appropriate Parameters. 8 | // And it's also fairly fast for everyday use. 9 | // 10 | // This package has been largely inspired by Ross Williams' 1993 paper "A Painless Guide to CRC Error Detection Algorithms". 11 | // A good list of parameter sets for various CRC algorithms can be found at http://reveng.sourceforge.net/crc-catalogue/. 12 | package crc 13 | 14 | // Parameters represents set of parameters defining a particular CRC algorithm. 15 | type Parameters struct { 16 | Width uint // Width of the CRC expressed in bits 17 | Polynomial uint64 // Polynomial used in this CRC calculation 18 | ReflectIn bool // ReflectIn indicates whether input bytes should be reflected 19 | ReflectOut bool // ReflectOut indicates whether input bytes should be reflected 20 | Init uint64 // Init is initial value for CRC calculation 21 | FinalXor uint64 // Xor is a value for final xor to be applied before returning result 22 | } 23 | 24 | var ( 25 | // X-25 CRC parameters, also known as CRC-16/IBM-SDLC, CRC-16/ISO-HDLC, CRC-B 26 | X25 = &Parameters{Width: 16, Polynomial: 0x1021, Init: 0xFFFF, ReflectIn: true, ReflectOut: true, FinalXor: 0xFFFF} 27 | // CCITT CRC parameters 28 | CCITT = &Parameters{Width: 16, Polynomial: 0x1021, Init: 0xFFFF, ReflectIn: false, ReflectOut: false, FinalXor: 0x0} 29 | // CRC16 CRC parameters, also known as ARC 30 | CRC16 = &Parameters{Width: 16, Polynomial: 0x8005, Init: 0x0000, ReflectIn: true, ReflectOut: true, FinalXor: 0x0} 31 | // XMODEM is a set of CRC parameters commonly referred as "XMODEM" 32 | XMODEM = &Parameters{Width: 16, Polynomial: 0x1021, Init: 0x0000, ReflectIn: false, ReflectOut: false, FinalXor: 0x0} 33 | // XMODEM2 is another set of CRC parameters commonly referred as "XMODEM" 34 | XMODEM2 = &Parameters{Width: 16, Polynomial: 0x8408, Init: 0x0000, ReflectIn: true, ReflectOut: true, FinalXor: 0x0} 35 | 36 | // CRC32 is by far the the most commonly used CRC-32 polynom and set of parameters 37 | CRC32 = &Parameters{Width: 32, Polynomial: 0x04C11DB7, Init: 0xFFFFFFFF, ReflectIn: true, ReflectOut: true, FinalXor: 0xFFFFFFFF} 38 | // IEEE is an alias to CRC32 39 | IEEE = CRC32 40 | // Castagnoli polynomial. used in iSCSI. And also provided by hash/crc32 package. 41 | Castagnoli = &Parameters{Width: 32, Polynomial: 0x1EDC6F41, Init: 0xFFFFFFFF, ReflectIn: true, ReflectOut: true, FinalXor: 0xFFFFFFFF} 42 | // CRC32C is an alias to Castagnoli 43 | CRC32C = Castagnoli 44 | // Koopman polynomial 45 | Koopman = &Parameters{Width: 32, Polynomial: 0x741B8CD7, Init: 0xFFFFFFFF, ReflectIn: true, ReflectOut: true, FinalXor: 0xFFFFFFFF} 46 | 47 | // CRC64ISO is set of parameters commonly known as CRC64-ISO 48 | CRC64ISO = &Parameters{Width: 64, Polynomial: 0x000000000000001B, Init: 0xFFFFFFFFFFFFFFFF, ReflectIn: true, ReflectOut: true, FinalXor: 0xFFFFFFFFFFFFFFFF} 49 | // CRC64ECMA is set of parameters commonly known as CRC64-ECMA 50 | CRC64ECMA = &Parameters{Width: 64, Polynomial: 0x42F0E1EBA9EA3693, Init: 0xFFFFFFFFFFFFFFFF, ReflectIn: true, ReflectOut: true, FinalXor: 0xFFFFFFFFFFFFFFFF} 51 | ) 52 | 53 | // reflect reverses order of last count bits 54 | func reflect(in uint64, count uint) uint64 { 55 | ret := in 56 | for idx := uint(0); idx < count; idx++ { 57 | srcbit := uint64(1) << idx 58 | dstbit := uint64(1) << (count - idx - 1) 59 | if (in & srcbit) != 0 { 60 | ret |= dstbit 61 | } else { 62 | ret = ret & (^dstbit) 63 | } 64 | } 65 | return ret 66 | } 67 | 68 | // CalculateCRC implements simple straight forward bit by bit calculation. 69 | // It is relatively slow for large amounts of data, but does not require 70 | // any preparation steps. As a result, it might be faster in some cases 71 | // then building a table required for faster calculation. 72 | // 73 | // Note: this implementation follows section 8 ("A Straightforward CRC Implementation") 74 | // of Ross N. Williams paper as even though final/sample implementation of this algorithm 75 | // provided near the end of that paper (and followed by most other implementations) 76 | // is a bit faster, it does not work for polynomials shorter then 8 bits. And if you need 77 | // speed, you shoud probably be using table based implementation anyway. 78 | func CalculateCRC(crcParams *Parameters, data []byte) uint64 { 79 | 80 | curValue := crcParams.Init 81 | topBit := uint64(1) << (crcParams.Width - 1) 82 | mask := (topBit << 1) - 1 83 | 84 | for i := 0; i < len(data); i++ { 85 | var curByte = uint64(data[i]) & 0x00FF 86 | if crcParams.ReflectIn { 87 | curByte = reflect(curByte, 8) 88 | } 89 | for j := uint64(0x0080); j != 0; j >>= 1 { 90 | bit := curValue & topBit 91 | curValue <<= 1 92 | if (curByte & j) != 0 { 93 | bit = bit ^ topBit 94 | } 95 | if bit != 0 { 96 | curValue = curValue ^ crcParams.Polynomial 97 | } 98 | } 99 | } 100 | if crcParams.ReflectOut { 101 | curValue = reflect(curValue, crcParams.Width) 102 | } 103 | 104 | curValue = curValue ^ crcParams.FinalXor 105 | 106 | return curValue & mask 107 | } 108 | 109 | // Table represents the partial evaluation of a checksum using table-driven 110 | // implementation. It is essentially immutable once initialized and thread safe as a result. 111 | type Table struct { 112 | crcParams Parameters 113 | crctable []uint64 114 | mask uint64 115 | initValue uint64 116 | } 117 | 118 | // NewTable creates and initializes a new Table for the CRC algorithm specified by the crcParams. 119 | func NewTable(crcParams *Parameters) *Table { 120 | ret := &Table{crcParams: *crcParams} 121 | ret.mask = (uint64(1) << crcParams.Width) - 1 122 | ret.crctable = make([]uint64, 256, 256) 123 | ret.initValue = crcParams.Init 124 | if crcParams.ReflectIn { 125 | ret.initValue = reflect(crcParams.Init, crcParams.Width) 126 | } 127 | 128 | tmp := make([]byte, 1, 1) 129 | tableParams := *crcParams 130 | tableParams.Init = 0 131 | tableParams.ReflectOut = tableParams.ReflectIn 132 | tableParams.FinalXor = 0 133 | for i := 0; i < 256; i++ { 134 | tmp[0] = byte(i) 135 | ret.crctable[i] = CalculateCRC(&tableParams, tmp) 136 | } 137 | return ret 138 | } 139 | 140 | // InitCrc returns a stating value for a new CRC calculation 141 | func (t *Table) InitCrc() uint64 { 142 | return t.initValue 143 | } 144 | 145 | // UpdateCrc process supplied bytes and updates current (partial) CRC accordingly. 146 | // It can be called repetitively to process larger data in chunks. 147 | func (t *Table) UpdateCrc(curValue uint64, p []byte) uint64 { 148 | if t.crcParams.ReflectIn { 149 | for _, v := range p { 150 | curValue = t.crctable[(byte(curValue)^v)&0xFF] ^ (curValue >> 8) 151 | } 152 | } else if t.crcParams.Width < 8 { 153 | for _, v := range p { 154 | curValue = t.crctable[((((byte)(curValue<<(8-t.crcParams.Width)))^v)&0xFF)] ^ (curValue << 8) 155 | } 156 | } else { 157 | for _, v := range p { 158 | curValue = t.crctable[((byte(curValue>>(t.crcParams.Width-8))^v)&0xFF)] ^ (curValue << 8) 159 | } 160 | } 161 | return curValue 162 | } 163 | 164 | // CRC returns CRC value for the data processed so far. 165 | func (t *Table) CRC(curValue uint64) uint64 { 166 | ret := curValue 167 | 168 | if t.crcParams.ReflectOut != t.crcParams.ReflectIn { 169 | ret = reflect(ret, t.crcParams.Width) 170 | } 171 | return (ret ^ t.crcParams.FinalXor) & t.mask 172 | } 173 | 174 | // CRC8 is a convenience method to spare end users from explicit type conversion every time this package is used. 175 | // Underneath, it just calls CRC() method. 176 | func (t *Table) CRC8(curValue uint64) uint8 { 177 | return uint8(t.CRC(curValue)) 178 | } 179 | 180 | // CRC16 is a convenience method to spare end users from explicit type conversion every time this package is used. 181 | // Underneath, it just calls CRC() method. 182 | func (t *Table) CRC16(curValue uint64) uint16 { 183 | return uint16(t.CRC(curValue)) 184 | } 185 | 186 | // CRC32 is a convenience method to spare end users from explicit type conversion every time this package is used. 187 | // Underneath, it just calls CRC() method. 188 | func (t *Table) CRC32(curValue uint64) uint32 { 189 | return uint32(t.CRC(curValue)) 190 | } 191 | 192 | // CalculateCRC is a convenience function allowing to calculate CRC in one call. 193 | func (t *Table) CalculateCRC(data []byte) uint64 { 194 | crc := t.InitCrc() 195 | crc = t.UpdateCrc(crc, data) 196 | return t.CRC(crc) 197 | } 198 | 199 | // Hash represents the partial evaluation of a checksum using table-driven 200 | // implementation. It also implements hash.Hash interface. 201 | type Hash struct { 202 | table *Table 203 | curValue uint64 204 | size uint 205 | } 206 | 207 | // Size returns the number of bytes Sum will return. 208 | // See hash.Hash interface. 209 | func (h *Hash) Size() int { return int(h.size) } 210 | 211 | // BlockSize returns the hash's underlying block size. 212 | // The Write method must be able to accept any amount 213 | // of data, but it may operate more efficiently if all writes 214 | // are a multiple of the block size. 215 | // See hash.Hash interface. 216 | func (h *Hash) BlockSize() int { return 1 } 217 | 218 | // Reset resets the Hash to its initial state. 219 | // See hash.Hash interface. 220 | func (h *Hash) Reset() { 221 | h.curValue = h.table.InitCrc() 222 | } 223 | 224 | // Sum appends the current hash to b and returns the resulting slice. 225 | // It does not change the underlying hash state. 226 | // See hash.Hash interface. 227 | func (h *Hash) Sum(in []byte) []byte { 228 | s := h.CRC() 229 | for i := h.size; i > 0; { 230 | i-- 231 | in = append(in, byte(s>>(8*i))) 232 | } 233 | return in 234 | } 235 | 236 | // Write implements io.Writer interface which is part of hash.Hash interface. 237 | func (h *Hash) Write(p []byte) (n int, err error) { 238 | h.Update(p) 239 | return len(p), nil 240 | } 241 | 242 | // Update updates process supplied bytes and updates current (partial) CRC accordingly. 243 | func (h *Hash) Update(p []byte) { 244 | h.curValue = h.table.UpdateCrc(h.curValue, p) 245 | } 246 | 247 | // CRC returns current CRC value for the data processed so far. 248 | func (h *Hash) CRC() uint64 { 249 | return h.table.CRC(h.curValue) 250 | } 251 | 252 | // CalculateCRC is a convenience function allowing to calculate CRC in one call. 253 | func (h *Hash) CalculateCRC(data []byte) uint64 { 254 | return h.table.CalculateCRC(data) 255 | } 256 | 257 | // NewHashWithTable creates a new Hash instance configured for table driven 258 | // CRC calculation using a Table instance created elsewhere. 259 | func NewHashWithTable(table *Table) *Hash { 260 | ret := &Hash{table: table} 261 | ret.size = (table.crcParams.Width + 7) / 8 // smalest number of bytes enough to store produced crc 262 | ret.Reset() 263 | return ret 264 | } 265 | 266 | // NewHash creates a new Hash instance configured for table driven 267 | // CRC calculation according to parameters specified. 268 | func NewHash(crcParams *Parameters) *Hash { 269 | return NewHashWithTable(NewTable(crcParams)) 270 | } 271 | 272 | // CRC8 is a convenience method to spare end users from explicit type conversion every time this package is used. 273 | // Underneath, it just calls CRC() method. 274 | func (h *Hash) CRC8() uint8 { 275 | return h.table.CRC8(h.curValue) 276 | } 277 | 278 | // CRC16 is a convenience method to spare end users from explicit type conversion every time this package is used. 279 | // Underneath, it just calls CRC() method. 280 | func (h *Hash) CRC16() uint16 { 281 | return h.table.CRC16(h.curValue) 282 | } 283 | 284 | // CRC32 is a convenience method to spare end users from explicit type conversion every time this package is used. 285 | // Underneath, it just calls CRC() method. 286 | func (h *Hash) CRC32() uint32 { 287 | return h.table.CRC32(h.curValue) 288 | } 289 | 290 | // Table used by this Hash under the hood 291 | func (h *Hash) Table() *Table { 292 | return h.table 293 | } 294 | -------------------------------------------------------------------------------- /crc_test.go: -------------------------------------------------------------------------------- 1 | package crc 2 | 3 | import ( 4 | "hash" 5 | "testing" 6 | ) 7 | 8 | func TestCRCAlgorithms(t *testing.T) { 9 | 10 | doTest := func(crcParams *Parameters, data string, crc uint64) { 11 | calculated := CalculateCRC(crcParams, []byte(data)) 12 | if calculated != crc { 13 | t.Errorf("Incorrect CRC 0x%04x calculated for %s (should be 0x%04x)", calculated, data, crc) 14 | } 15 | 16 | // same test using table driven 17 | tableDriven := NewHash(crcParams) 18 | calculated = tableDriven.CalculateCRC([]byte(data)) 19 | if calculated != crc { 20 | t.Errorf("Incorrect CRC 0x%04x calculated for %s (should be 0x%04x)", calculated, data, crc) 21 | } 22 | 23 | // same test feeding data in chunks of different size 24 | tableDriven.Reset() 25 | var start = 0 26 | var step = 1 27 | for start < len(data) { 28 | end := start + step 29 | if end > len(data) { 30 | end = len(data) 31 | } 32 | tableDriven.Update([]byte(data[start:end])) 33 | start = end 34 | step *= 2 35 | } 36 | calculated = tableDriven.CRC() 37 | if calculated != crc { 38 | t.Errorf("Incorrect CRC 0x%04x calculated for %s (should be 0x%04x)", calculated, data, crc) 39 | } 40 | 41 | // Test helper methods return correct values as well 42 | if crcParams.Width == 8 { 43 | crc8 := tableDriven.CRC8() 44 | if crc8 != uint8(crc&0x00FF) { 45 | t.Errorf("Incorrect CRC8 0x%02x retrived %s (should be 0x%02x)", crc8, data, crc) 46 | } 47 | } else if crcParams.Width == 16 { 48 | crc16 := tableDriven.CRC16() 49 | if crc16 != uint16(crc&0x00FFFF) { 50 | t.Errorf("Incorrect CRC16 0x%04x retrived %s (should be 0x%04x)", crc16, data, crc) 51 | } 52 | } else if crcParams.Width == 32 { 53 | crc32 := tableDriven.CRC32() 54 | if crc32 != uint32(crc&0x00FFFFFFFF) { 55 | t.Errorf("Incorrect CRC8 0x%08x retrived %s (should be 0x%08x)", crc32, data, crc) 56 | } 57 | } 58 | 59 | // Test Hash's table directly and see there is no difference 60 | table := tableDriven.Table() 61 | calculated = table.CalculateCRC([]byte(data)) 62 | if calculated != crc { 63 | t.Errorf("Incorrect CRC 0x%04x calculated for %s (should be 0x%04x)", calculated, data, crc) 64 | } 65 | 66 | } 67 | 68 | doTest(X25, "123456789", 0x906E) 69 | doTest(X25, "12345678901234567890", 0xA286) 70 | doTest(X25, "Introduction on CRC calculations", 0xF9B6) 71 | doTest(X25, "Whenever digital data is stored or interfaced, data corruption might occur. Since the beginning of computer science, people have been thinking of ways to deal with this type of problem. For serial data they came up with the solution to attach a parity bit to each sent byte. This simple detection mechanism works if an odd number of bits in a byte changes, but an even number of false bits in one byte will not be detected by the parity check. To overcome this problem people have searched for mathematical sound mechanisms to detect multiple false bits.", 0x68B1) 72 | 73 | doTest(CCITT, "123456789", 0x29B1) 74 | doTest(CCITT, "12345678901234567890", 0xDA31) 75 | doTest(CCITT, "Introduction on CRC calculations", 0xC87E) 76 | doTest(CCITT, "Whenever digital data is stored or interfaced, data corruption might occur. Since the beginning of computer science, people have been thinking of ways to deal with this type of problem. For serial data they came up with the solution to attach a parity bit to each sent byte. This simple detection mechanism works if an odd number of bits in a byte changes, but an even number of false bits in one byte will not be detected by the parity check. To overcome this problem people have searched for mathematical sound mechanisms to detect multiple false bits.", 0xD6ED) 77 | 78 | doTest(XMODEM, "123456789", 0x31C3) 79 | doTest(XMODEM, "12345678901234567890", 0x2C89) 80 | doTest(XMODEM, "Introduction on CRC calculations", 0x3932) 81 | doTest(XMODEM, "Whenever digital data is stored or interfaced, data corruption might occur. Since the beginning of computer science, people have been thinking of ways to deal with this type of problem. For serial data they came up with the solution to attach a parity bit to each sent byte. This simple detection mechanism works if an odd number of bits in a byte changes, but an even number of false bits in one byte will not be detected by the parity check. To overcome this problem people have searched for mathematical sound mechanisms to detect multiple false bits.", 0x4E86) 82 | 83 | doTest(XMODEM2, "123456789", 0x0C73) 84 | doTest(XMODEM2, "12345678901234567890", 0x122E) 85 | doTest(XMODEM2, "Introduction on CRC calculations", 0x0638) 86 | doTest(XMODEM2, "Whenever digital data is stored or interfaced, data corruption might occur. Since the beginning of computer science, people have been thinking of ways to deal with this type of problem. For serial data they came up with the solution to attach a parity bit to each sent byte. This simple detection mechanism works if an odd number of bits in a byte changes, but an even number of false bits in one byte will not be detected by the parity check. To overcome this problem people have searched for mathematical sound mechanisms to detect multiple false bits.", 0x187A) 87 | 88 | doTest(CRC32, "123456789", 0xCBF43926) 89 | doTest(CRC32, "12345678901234567890", 0x906319F2) 90 | doTest(CRC32, "Introduction on CRC calculations", 0x814F2B45) 91 | doTest(CRC32, "Whenever digital data is stored or interfaced, data corruption might occur. Since the beginning of computer science, people have been thinking of ways to deal with this type of problem. For serial data they came up with the solution to attach a parity bit to each sent byte. This simple detection mechanism works if an odd number of bits in a byte changes, but an even number of false bits in one byte will not be detected by the parity check. To overcome this problem people have searched for mathematical sound mechanisms to detect multiple false bits.", 0x8F273817) 92 | 93 | doTest(Castagnoli, "123456789", 0xE3069283) 94 | doTest(Castagnoli, "12345678901234567890", 0xA8B4A6B9) 95 | doTest(Castagnoli, "Introduction on CRC calculations", 0x54F98A9E) 96 | doTest(Castagnoli, "Whenever digital data is stored or interfaced, data corruption might occur. Since the beginning of computer science, people have been thinking of ways to deal with this type of problem. For serial data they came up with the solution to attach a parity bit to each sent byte. This simple detection mechanism works if an odd number of bits in a byte changes, but an even number of false bits in one byte will not be detected by the parity check. To overcome this problem people have searched for mathematical sound mechanisms to detect multiple false bits.", 0x864FDAFC) 97 | 98 | doTest(Koopman, "123456789", 0x2D3DD0AE) 99 | doTest(Koopman, "12345678901234567890", 0xCC53DEAC) 100 | doTest(Koopman, "Introduction on CRC calculations", 0x1B8101F9) 101 | doTest(Koopman, "Whenever digital data is stored or interfaced, data corruption might occur. Since the beginning of computer science, people have been thinking of ways to deal with this type of problem. For serial data they came up with the solution to attach a parity bit to each sent byte. This simple detection mechanism works if an odd number of bits in a byte changes, but an even number of false bits in one byte will not be detected by the parity check. To overcome this problem people have searched for mathematical sound mechanisms to detect multiple false bits.", 0xA41634B2) 102 | 103 | doTest(CRC64ISO, "123456789", 0xB90956C775A41001) 104 | doTest(CRC64ISO, "12345678901234567890", 0x8DB93749FB37B446) 105 | doTest(CRC64ISO, "Introduction on CRC calculations", 0xBAA81A1ED1A9209B) 106 | doTest(CRC64ISO, "Whenever digital data is stored or interfaced, data corruption might occur. Since the beginning of computer science, people have been thinking of ways to deal with this type of problem. For serial data they came up with the solution to attach a parity bit to each sent byte. This simple detection mechanism works if an odd number of bits in a byte changes, but an even number of false bits in one byte will not be detected by the parity check. To overcome this problem people have searched for mathematical sound mechanisms to detect multiple false bits.", 0x347969424A1A7628) 107 | 108 | doTest(CRC64ECMA, "123456789", 0x995DC9BBDF1939FA) 109 | doTest(CRC64ECMA, "12345678901234567890", 0x0DA1B82EF5085A4A) 110 | doTest(CRC64ECMA, "Introduction on CRC calculations", 0xCF8C40119AE90DCB) 111 | doTest(CRC64ECMA, "Whenever digital data is stored or interfaced, data corruption might occur. Since the beginning of computer science, people have been thinking of ways to deal with this type of problem. For serial data they came up with the solution to attach a parity bit to each sent byte. This simple detection mechanism works if an odd number of bits in a byte changes, but an even number of false bits in one byte will not be detected by the parity check. To overcome this problem people have searched for mathematical sound mechanisms to detect multiple false bits.", 0x31610F76CFB272A5) 112 | 113 | // More tests for various CRC algorithms (copied from java version) 114 | longText := "Whenever digital data is stored or interfaced, data corruption might occur. Since the beginning of computer science, people have been thinking of ways to deal with this type of problem. For serial data they came up with the solution to attach a parity bit to each sent byte. This simple detection mechanism works if an odd number of bits in a byte changes, but an even number of false bits in one byte will not be detected by the parity check. To overcome this problem people have searched for mathematical sound mechanisms to detect multiple false bits." 115 | 116 | testArrayData := make([]byte, 256) 117 | for i := 0; i < len(testArrayData); i++ { 118 | testArrayData[i] = byte(i & 0x0FF) 119 | } 120 | testArray := string(testArrayData) 121 | if len(testArray) != 256 { 122 | t.Fatalf("Logic error") 123 | } 124 | 125 | // merely a helper to make copying Spock test sets from java version of this library a bit easier 126 | doTestWithParameters := func(width uint, polynomial uint64, init uint64, reflectIn bool, reflectOut bool, finalXor uint64, crc uint64, testData string) { 127 | doTest(&Parameters{Width: width, Polynomial: polynomial, Init: init, ReflectIn: reflectIn, ReflectOut: reflectOut, FinalXor: finalXor}, testData, crc) 128 | } 129 | 130 | doTestWithParameters(3, 0x03, 0x00, false, false, 0x7, 0x04, "123456789") // CRC-3/GSM 131 | doTestWithParameters(3, 0x03, 0x00, false, false, 0x7, 0x06, longText) 132 | doTestWithParameters(3, 0x03, 0x00, false, false, 0x7, 0x02, testArray) 133 | doTestWithParameters(3, 0x03, 0x07, true, true, 0x0, 0x06, "123456789") // CRC-3/ROHC 134 | doTestWithParameters(3, 0x03, 0x07, true, true, 0x0, 0x03, longText) 135 | doTestWithParameters(4, 0x03, 0x00, true, true, 0x0, 0x07, "123456789") // CRC-4/ITU 136 | doTestWithParameters(4, 0x03, 0x0f, false, false, 0xf, 0x0b, "123456789") // CRC-4/INTERLAKEN 137 | doTestWithParameters(4, 0x03, 0x0f, false, false, 0xf, 0x01, longText) // CRC-4/INTERLAKEN 138 | doTestWithParameters(4, 0x03, 0x0f, false, false, 0xf, 0x07, testArray) // CRC-4/INTERLAKEN 139 | doTestWithParameters(5, 0x09, 0x09, false, false, 0x0, 0x00, "123456789") // CRC-5/EPC 140 | doTestWithParameters(5, 0x15, 0x00, true, true, 0x0, 0x07, "123456789") // CRC-5/ITU 141 | doTestWithParameters(6, 0x27, 0x3f, false, false, 0x0, 0x0d, "123456789") // CRC-6/CDMA2000-A 142 | doTestWithParameters(6, 0x07, 0x3f, false, false, 0x0, 0x3b, "123456789") // CRC-6/CDMA2000-B 143 | doTestWithParameters(6, 0x07, 0x3f, false, false, 0x0, 0x24, testArray) // CRC-6/CDMA2000-B 144 | doTestWithParameters(7, 0x09, 0x00, false, false, 0x0, 0x75, "123456789") // CRC-7 145 | doTestWithParameters(7, 0x09, 0x00, false, false, 0x0, 0x78, testArray) // CRC-7 146 | doTestWithParameters(7, 0x4f, 0x7f, true, true, 0x0, 0x53, "123456789") // CRC-7/ROHC 147 | 148 | doTestWithParameters(8, 0x07, 0x00, false, false, 0x00, 0xf4, "123456789") // CRC-8 149 | doTestWithParameters(8, 0xa7, 0x00, true, true, 0x00, 0x26, "123456789") // CRC-8/BLUETOOTH 150 | doTestWithParameters(8, 0x07, 0x00, false, false, 0x55, 0xa1, "123456789") // CRC-8/ITU 151 | doTestWithParameters(8, 0x9b, 0x00, true, true, 0x00, 0x25, "123456789") // CRC-8/WCDMA 152 | doTestWithParameters(8, 0x31, 0x00, true, true, 0x00, 0xa1, "123456789") // CRC-8/MAXIM 153 | 154 | doTestWithParameters(10, 0x233, 0x000, false, false, 0x000, 0x199, "123456789") // CRC-10 155 | 156 | doTestWithParameters(12, 0xd31, 0x00, false, false, 0xfff, 0x0b34, "123456789") // CRC-12/GSM 157 | doTestWithParameters(12, 0x80f, 0x00, false, true, 0x00, 0x0daf, "123456789") // CRC-12/UMTS 158 | doTestWithParameters(13, 0x1cf5, 0x00, false, false, 0x00, 0x04fa, "123456789") // CRC-13/BBC 159 | doTestWithParameters(14, 0x0805, 0x00, true, true, 0x00, 0x082d, "123456789") // CRC-14/DARC 160 | doTestWithParameters(14, 0x202d, 0x00, false, false, 0x3fff, 0x30ae, "123456789") // CRC-14/GSM 161 | 162 | doTestWithParameters(15, 0x4599, 0x00, false, false, 0x00, 0x059e, "123456789") // CRC-15 163 | doTestWithParameters(15, 0x4599, 0x00, false, false, 0x00, 0x2857, longText) 164 | doTestWithParameters(15, 0x6815, 0x00, false, false, 0x0001, 0x2566, "123456789") // CRC-15/MPT1327 165 | 166 | doTestWithParameters(21, 0x102899, 0x000000, false, false, 0x000000, 0x0ed841, "123456789") // CRC-21/CAN-FD 167 | doTestWithParameters(24, 0x864cfb, 0xb704ce, false, false, 0x000000, 0x21cf02, "123456789") // CRC-24 168 | doTestWithParameters(24, 0x5d6dcb, 0xfedcba, false, false, 0x000000, 0x7979bd, "123456789") // CRC-24/FLEXRAY-A 169 | doTestWithParameters(24, 0x00065b, 0x555555, true, true, 0x000000, 0xc25a56, "123456789") // "CRC-24/BLE" 170 | 171 | doTestWithParameters(31, 0x04c11db7, 0x7fffffff, false, false, 0x7fffffff, 0x0ce9e46c, "123456789") // CRC-31/PHILIPS 172 | } 173 | 174 | func TestSizeMethods(t *testing.T) { 175 | testWidth := func(width uint, expectedSize int) { 176 | h := NewHash(&Parameters{Width: width, Polynomial: 1}) 177 | s := h.Size() 178 | if s != expectedSize { 179 | t.Errorf("Incorrect Size calculated for width %d: %d when should be %d", width, s, expectedSize) 180 | } 181 | bs := h.BlockSize() 182 | if bs != 1 { 183 | t.Errorf("Incorrect Block Size returned for width %d: %d when should always be 1", width, bs) 184 | } 185 | } 186 | 187 | testWidth(3, 1) 188 | testWidth(8, 1) 189 | testWidth(12, 2) 190 | testWidth(16, 2) 191 | testWidth(32, 4) 192 | testWidth(64, 8) 193 | 194 | } 195 | 196 | func TestHashInterface(t *testing.T) { 197 | doTest := func(crcParams *Parameters, data string, crc uint64) { 198 | // same test using table driven 199 | var h hash.Hash = NewHash(crcParams) 200 | 201 | // same test feeding data in chunks of different size 202 | h.Reset() 203 | var start = 0 204 | var step = 1 205 | for start < len(data) { 206 | end := start + step 207 | if end > len(data) { 208 | end = len(data) 209 | } 210 | h.Write([]byte(data[start:end])) 211 | start = end 212 | step *= 2 213 | } 214 | 215 | buf := make([]byte, 0, 0) 216 | buf = h.Sum(buf) 217 | 218 | if len(buf) != h.Size() { 219 | t.Errorf("Wrong number of bytes appended by Sum(): %d when should be %d", len(buf), h.Size()) 220 | } 221 | 222 | calculated := uint64(0) 223 | for _, b := range buf { 224 | calculated <<= 8 225 | calculated += uint64(b) 226 | } 227 | 228 | if calculated != crc { 229 | t.Errorf("Incorrect CRC 0x%04x calculated for %s (should be 0x%04x)", calculated, data, crc) 230 | } 231 | } 232 | 233 | doTest(&Parameters{Width: 8, Polynomial: 0x07, Init: 0x00, ReflectIn: false, ReflectOut: false, FinalXor: 0x00}, "123456789", 0xf4) 234 | doTest(CCITT, "12345678901234567890", 0xDA31) 235 | doTest(CRC64ECMA, "Introduction on CRC calculations", 0xCF8C40119AE90DCB) 236 | doTest(CRC32C, "Whenever digital data is stored or interfaced, data corruption might occur. Since the beginning of computer science, people have been thinking of ways to deal with this type of problem. For serial data they came up with the solution to attach a parity bit to each sent byte. This simple detection mechanism works if an odd number of bits in a byte changes, but an even number of false bits in one byte will not be detected by the parity check. To overcome this problem people have searched for mathematical sound mechanisms to detect multiple false bits.", 0x864FDAFC) 237 | } 238 | 239 | func BenchmarkCCITT(b *testing.B) { 240 | data := []byte("Whenever digital data is stored or interfaced, data corruption might occur. Since the beginning of computer science, people have been thinking of ways to deal with this type of problem. For serial data they came up with the solution to attach a parity bit to each sent byte. This simple detection mechanism works if an odd number of bits in a byte changes, but an even number of false bits in one byte will not be detected by the parity check. To overcome this problem people have searched for mathematical sound mechanisms to detect multiple false bits.") 241 | for i := 0; i < b.N; i++ { 242 | tableDriven := NewHash(CCITT) 243 | tableDriven.Update(data) 244 | tableDriven.CRC() 245 | } 246 | } 247 | --------------------------------------------------------------------------------