1// Copyright 2009 The Go Authors. All rights reserved.
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 crc32 implements the 32-bit cyclic redundancy check, or CRC-32,
6// checksum. See https://en.wikipedia.org/wiki/Cyclic_redundancy_check for
7// information.
8//
9// Polynomials are represented in LSB-first form also known as reversed representation.
10//
11// See https://en.wikipedia.org/wiki/Mathematics_of_cyclic_redundancy_checks#Reversed_representations_and_reciprocal_polynomials
12// for information.
13package crc32
14
15import (
16	"errors"
17	"hash"
18	"internal/byteorder"
19	"sync"
20	"sync/atomic"
21)
22
23// The size of a CRC-32 checksum in bytes.
24const Size = 4
25
26// Predefined polynomials.
27const (
28	// IEEE is by far and away the most common CRC-32 polynomial.
29	// Used by ethernet (IEEE 802.3), v.42, fddi, gzip, zip, png, ...
30	IEEE = 0xedb88320
31
32	// Castagnoli's polynomial, used in iSCSI.
33	// Has better error detection characteristics than IEEE.
34	// https://dx.doi.org/10.1109/26.231911
35	Castagnoli = 0x82f63b78
36
37	// Koopman's polynomial.
38	// Also has better error detection characteristics than IEEE.
39	// https://dx.doi.org/10.1109/DSN.2002.1028931
40	Koopman = 0xeb31d82e
41)
42
43// Table is a 256-word table representing the polynomial for efficient processing.
44type Table [256]uint32
45
46// This file makes use of functions implemented in architecture-specific files.
47// The interface that they implement is as follows:
48//
49//    // archAvailableIEEE reports whether an architecture-specific CRC32-IEEE
50//    // algorithm is available.
51//    archAvailableIEEE() bool
52//
53//    // archInitIEEE initializes the architecture-specific CRC3-IEEE algorithm.
54//    // It can only be called if archAvailableIEEE() returns true.
55//    archInitIEEE()
56//
57//    // archUpdateIEEE updates the given CRC32-IEEE. It can only be called if
58//    // archInitIEEE() was previously called.
59//    archUpdateIEEE(crc uint32, p []byte) uint32
60//
61//    // archAvailableCastagnoli reports whether an architecture-specific
62//    // CRC32-C algorithm is available.
63//    archAvailableCastagnoli() bool
64//
65//    // archInitCastagnoli initializes the architecture-specific CRC32-C
66//    // algorithm. It can only be called if archAvailableCastagnoli() returns
67//    // true.
68//    archInitCastagnoli()
69//
70//    // archUpdateCastagnoli updates the given CRC32-C. It can only be called
71//    // if archInitCastagnoli() was previously called.
72//    archUpdateCastagnoli(crc uint32, p []byte) uint32
73
74// castagnoliTable points to a lazily initialized Table for the Castagnoli
75// polynomial. MakeTable will always return this value when asked to make a
76// Castagnoli table so we can compare against it to find when the caller is
77// using this polynomial.
78var castagnoliTable *Table
79var castagnoliTable8 *slicing8Table
80var updateCastagnoli func(crc uint32, p []byte) uint32
81var castagnoliOnce sync.Once
82var haveCastagnoli atomic.Bool
83
84func castagnoliInit() {
85	castagnoliTable = simpleMakeTable(Castagnoli)
86
87	if archAvailableCastagnoli() {
88		archInitCastagnoli()
89		updateCastagnoli = archUpdateCastagnoli
90	} else {
91		// Initialize the slicing-by-8 table.
92		castagnoliTable8 = slicingMakeTable(Castagnoli)
93		updateCastagnoli = func(crc uint32, p []byte) uint32 {
94			return slicingUpdate(crc, castagnoliTable8, p)
95		}
96	}
97
98	haveCastagnoli.Store(true)
99}
100
101// IEEETable is the table for the [IEEE] polynomial.
102var IEEETable = simpleMakeTable(IEEE)
103
104// ieeeTable8 is the slicing8Table for IEEE
105var ieeeTable8 *slicing8Table
106var updateIEEE func(crc uint32, p []byte) uint32
107var ieeeOnce sync.Once
108
109func ieeeInit() {
110	if archAvailableIEEE() {
111		archInitIEEE()
112		updateIEEE = archUpdateIEEE
113	} else {
114		// Initialize the slicing-by-8 table.
115		ieeeTable8 = slicingMakeTable(IEEE)
116		updateIEEE = func(crc uint32, p []byte) uint32 {
117			return slicingUpdate(crc, ieeeTable8, p)
118		}
119	}
120}
121
122// MakeTable returns a [Table] constructed from the specified polynomial.
123// The contents of this [Table] must not be modified.
124func MakeTable(poly uint32) *Table {
125	switch poly {
126	case IEEE:
127		ieeeOnce.Do(ieeeInit)
128		return IEEETable
129	case Castagnoli:
130		castagnoliOnce.Do(castagnoliInit)
131		return castagnoliTable
132	default:
133		return simpleMakeTable(poly)
134	}
135}
136
137// digest represents the partial evaluation of a checksum.
138type digest struct {
139	crc uint32
140	tab *Table
141}
142
143// New creates a new [hash.Hash32] computing the CRC-32 checksum using the
144// polynomial represented by the [Table]. Its Sum method will lay the
145// value out in big-endian byte order. The returned Hash32 also
146// implements [encoding.BinaryMarshaler] and [encoding.BinaryUnmarshaler] to
147// marshal and unmarshal the internal state of the hash.
148func New(tab *Table) hash.Hash32 {
149	if tab == IEEETable {
150		ieeeOnce.Do(ieeeInit)
151	}
152	return &digest{0, tab}
153}
154
155// NewIEEE creates a new [hash.Hash32] computing the CRC-32 checksum using
156// the [IEEE] polynomial. Its Sum method will lay the value out in
157// big-endian byte order. The returned Hash32 also implements
158// [encoding.BinaryMarshaler] and [encoding.BinaryUnmarshaler] to marshal
159// and unmarshal the internal state of the hash.
160func NewIEEE() hash.Hash32 { return New(IEEETable) }
161
162func (d *digest) Size() int { return Size }
163
164func (d *digest) BlockSize() int { return 1 }
165
166func (d *digest) Reset() { d.crc = 0 }
167
168const (
169	magic         = "crc\x01"
170	marshaledSize = len(magic) + 4 + 4
171)
172
173func (d *digest) MarshalBinary() ([]byte, error) {
174	b := make([]byte, 0, marshaledSize)
175	b = append(b, magic...)
176	b = byteorder.BeAppendUint32(b, tableSum(d.tab))
177	b = byteorder.BeAppendUint32(b, d.crc)
178	return b, nil
179}
180
181func (d *digest) UnmarshalBinary(b []byte) error {
182	if len(b) < len(magic) || string(b[:len(magic)]) != magic {
183		return errors.New("hash/crc32: invalid hash state identifier")
184	}
185	if len(b) != marshaledSize {
186		return errors.New("hash/crc32: invalid hash state size")
187	}
188	if tableSum(d.tab) != byteorder.BeUint32(b[4:]) {
189		return errors.New("hash/crc32: tables do not match")
190	}
191	d.crc = byteorder.BeUint32(b[8:])
192	return nil
193}
194
195func update(crc uint32, tab *Table, p []byte, checkInitIEEE bool) uint32 {
196	switch {
197	case haveCastagnoli.Load() && tab == castagnoliTable:
198		return updateCastagnoli(crc, p)
199	case tab == IEEETable:
200		if checkInitIEEE {
201			ieeeOnce.Do(ieeeInit)
202		}
203		return updateIEEE(crc, p)
204	default:
205		return simpleUpdate(crc, tab, p)
206	}
207}
208
209// Update returns the result of adding the bytes in p to the crc.
210func Update(crc uint32, tab *Table, p []byte) uint32 {
211	// Unfortunately, because IEEETable is exported, IEEE may be used without a
212	// call to MakeTable. We have to make sure it gets initialized in that case.
213	return update(crc, tab, p, true)
214}
215
216func (d *digest) Write(p []byte) (n int, err error) {
217	// We only create digest objects through New() which takes care of
218	// initialization in this case.
219	d.crc = update(d.crc, d.tab, p, false)
220	return len(p), nil
221}
222
223func (d *digest) Sum32() uint32 { return d.crc }
224
225func (d *digest) Sum(in []byte) []byte {
226	s := d.Sum32()
227	return append(in, byte(s>>24), byte(s>>16), byte(s>>8), byte(s))
228}
229
230// Checksum returns the CRC-32 checksum of data
231// using the polynomial represented by the [Table].
232func Checksum(data []byte, tab *Table) uint32 { return Update(0, tab, data) }
233
234// ChecksumIEEE returns the CRC-32 checksum of data
235// using the [IEEE] polynomial.
236func ChecksumIEEE(data []byte) uint32 {
237	ieeeOnce.Do(ieeeInit)
238	return updateIEEE(0, data)
239}
240
241// tableSum returns the IEEE checksum of table t.
242func tableSum(t *Table) uint32 {
243	var a [1024]byte
244	b := a[:0]
245	if t != nil {
246		for _, x := range t {
247			b = byteorder.BeAppendUint32(b, x)
248		}
249	}
250	return ChecksumIEEE(b)
251}
252