mirror of
https://github.com/espressif/openthread.git
synced 2026-08-02 09:07:47 +00:00
[common] update and enhance CRC calculation (#11182)
This commit updates and enhances the CRC module. It updates the implementation to allow both CRC16 and CRC32 calculation with different polynomials. It adds new `Feed()` methods to add bytes from a buffer or from a message into CRC computation. It also adds a unit test to cover CRC calculation (both CRC16 and CRC32).
This commit is contained in:
+2
-2
@@ -394,8 +394,8 @@ openthread_core_files = [
|
||||
"common/callback.hpp",
|
||||
"common/clearable.hpp",
|
||||
"common/const_cast.hpp",
|
||||
"common/crc16.cpp",
|
||||
"common/crc16.hpp",
|
||||
"common/crc.cpp",
|
||||
"common/crc.hpp",
|
||||
"common/data.cpp",
|
||||
"common/data.hpp",
|
||||
"common/debug.hpp",
|
||||
|
||||
@@ -101,7 +101,7 @@ set(COMMON_SOURCES
|
||||
coap/coap_secure.cpp
|
||||
common/appender.cpp
|
||||
common/binary_search.cpp
|
||||
common/crc16.cpp
|
||||
common/crc.cpp
|
||||
common/data.cpp
|
||||
common/error.cpp
|
||||
common/frame_builder.cpp
|
||||
|
||||
@@ -31,34 +31,62 @@
|
||||
* This file implements CRC16 computations.
|
||||
*/
|
||||
|
||||
#include "crc16.hpp"
|
||||
#include "crc.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
Crc16::Crc16(Polynomial aPolynomial)
|
||||
template <typename UintType> UintType CrcCalculator<UintType>::FeedByte(uint8_t aByte)
|
||||
{
|
||||
mPolynomial = static_cast<uint16_t>(aPolynomial);
|
||||
Init();
|
||||
}
|
||||
static constexpr UintType kMsb = kIsUint16 ? (1u << 15) : (1u << 31);
|
||||
static constexpr uint8_t kBitShift = kIsUint16 ? 8 : 24;
|
||||
|
||||
void Crc16::Update(uint8_t aByte)
|
||||
{
|
||||
uint8_t i;
|
||||
mCrc ^= (static_cast<UintType>(aByte) << kBitShift);
|
||||
|
||||
mCrc = mCrc ^ static_cast<uint16_t>(aByte << 8);
|
||||
i = 8;
|
||||
|
||||
do
|
||||
for (uint8_t i = 8; i > 0; i--)
|
||||
{
|
||||
if (mCrc & 0x8000)
|
||||
bool msbIsSet = (mCrc & kMsb);
|
||||
|
||||
mCrc <<= 1;
|
||||
|
||||
if (msbIsSet)
|
||||
{
|
||||
mCrc = static_cast<uint16_t>(mCrc << 1) ^ mPolynomial;
|
||||
mCrc ^= mPolynomial;
|
||||
}
|
||||
else
|
||||
{
|
||||
mCrc = static_cast<uint16_t>(mCrc << 1);
|
||||
}
|
||||
} while (--i);
|
||||
}
|
||||
|
||||
return mCrc;
|
||||
}
|
||||
|
||||
template <typename UintType> UintType CrcCalculator<UintType>::FeedBytes(const void *aBytes, uint16_t aLength)
|
||||
{
|
||||
const uint8_t *bytes = reinterpret_cast<const uint8_t *>(aBytes);
|
||||
|
||||
while (aLength-- > 0)
|
||||
{
|
||||
FeedByte(*bytes++);
|
||||
}
|
||||
|
||||
return mCrc;
|
||||
}
|
||||
|
||||
template <typename UintType>
|
||||
UintType CrcCalculator<UintType>::Feed(const Message &aMessage, const OffsetRange &aOffsetRange)
|
||||
{
|
||||
uint16_t length = aOffsetRange.GetLength();
|
||||
Message::Chunk chunk;
|
||||
|
||||
aMessage.GetFirstChunk(aOffsetRange.GetOffset(), length, chunk);
|
||||
|
||||
while (chunk.GetLength() > 0)
|
||||
{
|
||||
FeedBytes(chunk.GetBytes(), chunk.GetLength());
|
||||
aMessage.GetNextChunk(length, chunk);
|
||||
}
|
||||
|
||||
return mCrc;
|
||||
}
|
||||
|
||||
template class CrcCalculator<uint16_t>;
|
||||
template class CrcCalculator<uint32_t>;
|
||||
|
||||
} // namespace ot
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (c) 2016, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file includes definitions for CRC computations.
|
||||
*/
|
||||
|
||||
#ifndef CRC_HPP_
|
||||
#define CRC_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include "common/message.hpp"
|
||||
#include "common/type_traits.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
constexpr uint16_t kCrc16CcittPolynomial = 0x1021; ///< CRC16-CCITT Polynomial (x^16 + x^12 + x^5 + 1)
|
||||
constexpr uint16_t kCrc16AnsiPolynomial = 0x8005; ///< CRC16-ANSI Polynomial (x^16 + x^15 + x^2 + 1)
|
||||
|
||||
/**
|
||||
* CRC32-ANSI Polynomial
|
||||
*
|
||||
* (x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1)
|
||||
*/
|
||||
constexpr uint32_t kCrc32AnsiPolynomial = 0x04c11db7;
|
||||
|
||||
/**
|
||||
* Implements CRC computations.
|
||||
*
|
||||
* @tparam UintType The unsigned int type indicating CRC bit width. MUST be either `uint16_t` or `uint32_t`.
|
||||
*/
|
||||
template <typename UintType> class CrcCalculator
|
||||
{
|
||||
constexpr static bool kIsUint16 = TypeTraits::IsSame<UintType, uint16_t>::kValue;
|
||||
constexpr static bool kIsUint32 = TypeTraits::IsSame<UintType, uint32_t>::kValue;
|
||||
|
||||
static_assert(kIsUint16 || kIsUint32, "UintType MUST be either `uint16_t` or `uint32_t`");
|
||||
|
||||
public:
|
||||
/**
|
||||
* Initializes the `CrcCalculator` object.
|
||||
*
|
||||
* @param[in] aPolynomial The polynomial to use for CRC calculation.
|
||||
*/
|
||||
explicit CrcCalculator(UintType aPolynomial)
|
||||
: mPolynomial(aPolynomial)
|
||||
, mCrc(0)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current CRC value.
|
||||
*
|
||||
* @returns The current CRC value.
|
||||
*/
|
||||
UintType GetCrc(void) const { return mCrc; }
|
||||
|
||||
/**
|
||||
* Feeds a byte value into the CRC computation.
|
||||
*
|
||||
* @param[in] aByte The byte value.
|
||||
*
|
||||
* @returns The current CRC value.
|
||||
*/
|
||||
UintType FeedByte(uint8_t aByte);
|
||||
|
||||
/**
|
||||
* Feeds a sequence of bytes into the CRC computation.
|
||||
*
|
||||
* @param[in] aBytes A pointer to buffer containing the bytes.
|
||||
* @param[in] aLength Number of bytes in @p aBytes.
|
||||
*
|
||||
* @returns The current CRC value.
|
||||
*/
|
||||
UintType FeedBytes(const void *aBytes, uint16_t aLength);
|
||||
|
||||
/**
|
||||
* Feed an object (all its bytes) into the CRC computation.
|
||||
*
|
||||
* @tparam ObjectType The object type.
|
||||
*
|
||||
* @param[in] aObject A reference to the object.
|
||||
*
|
||||
* @returns The current CRC value.
|
||||
*/
|
||||
template <typename ObjectType> UintType Feed(const ObjectType &aObject)
|
||||
{
|
||||
static_assert(!TypeTraits::IsPointer<ObjectType>::kValue, "ObjectType must not be a pointer");
|
||||
return FeedBytes(&aObject, sizeof(ObjectType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Feed bytes read from a given message within a given offset range into the CRC computation.
|
||||
*
|
||||
* @param[in] aMessage The message to read from.
|
||||
* @param[in] aOffsetRaneg The offset range in @p aMessage to read bytes from.
|
||||
*
|
||||
* @returns The current CRC value.
|
||||
*/
|
||||
UintType Feed(const Message &aMessage, const OffsetRange &aOffsetRange);
|
||||
|
||||
private:
|
||||
UintType mPolynomial;
|
||||
UintType mCrc;
|
||||
};
|
||||
|
||||
} // namespace ot
|
||||
|
||||
#endif // CRC_HPP_
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file includes definitions for CRC16 computations.
|
||||
*/
|
||||
|
||||
#ifndef CRC16_HPP_
|
||||
#define CRC16_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace ot {
|
||||
|
||||
/**
|
||||
* Implements CRC16 computations.
|
||||
*/
|
||||
class Crc16
|
||||
{
|
||||
public:
|
||||
enum Polynomial : uint16_t
|
||||
{
|
||||
kCcitt = 0x1021, ///< CRC16_CCITT
|
||||
kAnsi = 0x8005, ///< CRC16-ANSI
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes the object.
|
||||
*
|
||||
* @param[in] aPolynomial The polynomial value.
|
||||
*/
|
||||
explicit Crc16(Polynomial aPolynomial);
|
||||
|
||||
/**
|
||||
* Initializes the CRC16 computation.
|
||||
*/
|
||||
void Init(void) { mCrc = 0; }
|
||||
|
||||
/*c*
|
||||
* Feeds a byte value into the CRC16 computation.
|
||||
*
|
||||
* @param[in] aByte The byte value.
|
||||
*/
|
||||
void Update(uint8_t aByte);
|
||||
|
||||
/**
|
||||
* Gets the current CRC16 value.
|
||||
*
|
||||
* @returns The current CRC16 value.
|
||||
*/
|
||||
uint16_t Get(void) const { return mCrc; }
|
||||
|
||||
private:
|
||||
uint16_t mPolynomial;
|
||||
uint16_t mCrc;
|
||||
};
|
||||
|
||||
} // namespace ot
|
||||
|
||||
#endif // CRC16_HPP_
|
||||
@@ -69,6 +69,8 @@ struct otMessage
|
||||
|
||||
namespace ot {
|
||||
|
||||
template <typename UintType> class CrcCalculator;
|
||||
|
||||
namespace Crypto {
|
||||
|
||||
class AesCcm;
|
||||
@@ -272,6 +274,8 @@ static_assert(sizeof(Buffer) >= kBufferSize,
|
||||
class Message : public otMessage, public Buffer, public GetProvider<Message>
|
||||
{
|
||||
friend class Checksum;
|
||||
friend class CrcCalculator<uint16_t>;
|
||||
friend class CrcCalculator<uint32_t>;
|
||||
friend class Crypto::HmacSha256;
|
||||
friend class Crypto::Sha256;
|
||||
friend class Crypto::AesCcm;
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
#include "meshcop.hpp"
|
||||
|
||||
#include "common/crc16.hpp"
|
||||
#include "common/crc.hpp"
|
||||
#include "instance/instance.hpp"
|
||||
|
||||
namespace ot {
|
||||
@@ -244,17 +244,8 @@ bool SteeringData::Contains(const HashBitIndexes &aIndexes) const
|
||||
|
||||
void SteeringData::CalculateHashBitIndexes(const Mac::ExtAddress &aJoinerId, HashBitIndexes &aIndexes)
|
||||
{
|
||||
Crc16 ccitt(Crc16::kCcitt);
|
||||
Crc16 ansi(Crc16::kAnsi);
|
||||
|
||||
for (uint8_t b : aJoinerId.m8)
|
||||
{
|
||||
ccitt.Update(b);
|
||||
ansi.Update(b);
|
||||
}
|
||||
|
||||
aIndexes.mIndex[0] = ccitt.Get();
|
||||
aIndexes.mIndex[1] = ansi.Get();
|
||||
aIndexes.mIndex[0] = CrcCalculator<uint16_t>(kCrc16CcittPolynomial).Feed(aJoinerId);
|
||||
aIndexes.mIndex[1] = CrcCalculator<uint16_t>(kCrc16AnsiPolynomial).Feed(aJoinerId);
|
||||
}
|
||||
|
||||
void SteeringData::CalculateHashBitIndexes(const JoinerDiscerner &aDiscerner, HashBitIndexes &aIndexes)
|
||||
|
||||
@@ -205,6 +205,7 @@ ot_unit_test(checksum)
|
||||
ot_unit_test(child)
|
||||
ot_unit_test(child_table)
|
||||
ot_unit_test(cmd_line_parser)
|
||||
ot_unit_test(crc)
|
||||
ot_unit_test(data)
|
||||
ot_unit_test(dataset)
|
||||
ot_unit_test(dns)
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2025, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "common/crc.hpp"
|
||||
|
||||
#include "test_platform.h"
|
||||
#include "test_util.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
void TestCrc16(void)
|
||||
{
|
||||
struct TestCase
|
||||
{
|
||||
const uint8_t *mData;
|
||||
uint16_t mDataLength;
|
||||
uint16_t mExpectedCcittCrc16;
|
||||
uint16_t mExpectedAnsiCrc16;
|
||||
};
|
||||
|
||||
static const uint8_t kTestData1[] = {0xff};
|
||||
static const uint8_t kTestData2[] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39}; // "123456789"
|
||||
static const uint8_t kTestData3[] = {0x10, 0x20, 0x03, 0x15, 0xbe, 0xef, 0xca, 0xfe};
|
||||
|
||||
static const TestCase kTestCases[] = {
|
||||
{kTestData1, sizeof(kTestData1), 0x1ef0, 0x0202},
|
||||
{kTestData2, sizeof(kTestData2), 0x31c3, 0xfee8},
|
||||
{kTestData3, sizeof(kTestData3), 0x926a, 0x070c},
|
||||
};
|
||||
|
||||
printf("\nTestCrc16");
|
||||
|
||||
for (const TestCase &testCase : kTestCases)
|
||||
{
|
||||
CrcCalculator<uint16_t> ccitt(kCrc16CcittPolynomial);
|
||||
CrcCalculator<uint16_t> ansi(kCrc16AnsiPolynomial);
|
||||
|
||||
ccitt.FeedBytes(testCase.mData, testCase.mDataLength);
|
||||
ansi.FeedBytes(testCase.mData, testCase.mDataLength);
|
||||
|
||||
DumpBuffer("CRC16", testCase.mData, testCase.mDataLength);
|
||||
printf("-> CCIT: 0x%04x, ANSI: 0x%04x\n", ccitt.GetCrc(), ansi.GetCrc());
|
||||
|
||||
VerifyOrQuit(ccitt.GetCrc() == testCase.mExpectedCcittCrc16);
|
||||
VerifyOrQuit(ansi.GetCrc() == testCase.mExpectedAnsiCrc16);
|
||||
}
|
||||
}
|
||||
|
||||
void TestCrc32(void)
|
||||
{
|
||||
struct TestCase
|
||||
{
|
||||
const uint8_t *mData;
|
||||
uint16_t mDataLength;
|
||||
uint32_t mExpectedAnsiCrc32;
|
||||
};
|
||||
|
||||
static const uint8_t kTestData1[] = {0xff};
|
||||
static const uint8_t kTestData2[] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39}; // "123456789"
|
||||
static const uint8_t kTestData3[] = {0x10, 0x20, 0x03, 0x15, 0xbe, 0xef, 0xca, 0xfe};
|
||||
|
||||
static const TestCase kTestCases[] = {
|
||||
{kTestData1, sizeof(kTestData1), 0xb1f740b4},
|
||||
{kTestData2, sizeof(kTestData2), 0x89a1897f},
|
||||
{kTestData3, sizeof(kTestData3), 0xd651e770},
|
||||
};
|
||||
|
||||
printf("\nTestCrc32\n");
|
||||
|
||||
for (const TestCase &testCase : kTestCases)
|
||||
{
|
||||
CrcCalculator<uint32_t> crc32(kCrc32AnsiPolynomial);
|
||||
|
||||
crc32.FeedBytes(testCase.mData, testCase.mDataLength);
|
||||
|
||||
DumpBuffer("CRC32", testCase.mData, testCase.mDataLength);
|
||||
printf("-> 0x%08lx\n", ToUlong(crc32.GetCrc()));
|
||||
|
||||
VerifyOrQuit(crc32.GetCrc() == testCase.mExpectedAnsiCrc32);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ot
|
||||
|
||||
int main(void)
|
||||
{
|
||||
ot::TestCrc16();
|
||||
ot::TestCrc32();
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user