blob: bf41709a49199f142c51153e5b5d6b15cb6589ce [file] [log] [blame]
/*
* Copyright (c) 2024, 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 implements Verhoeff checksum calculation and validation.
*/
#include "verhoeff_checksum.hpp"
#if OPENTHREAD_CONFIG_VERHOEFF_CHECKSUM_ENABLE
#include "common/code_utils.hpp"
#include "common/string.hpp"
namespace ot {
namespace Utils {
uint8_t VerhoeffChecksum::Lookup(uint8_t aIndex, const uint8_t aCompressedArray[])
{
// The values in the array are [0-9]. To save space, two
// entries are saved as a single byte in @p aCompressedArray,
// such that higher 4-bit corresponds to one entry, and the
// lower 4-bit to the next entry.
uint8_t result = aCompressedArray[aIndex / 2];
if ((aIndex & 1) == 0)
{
result >>= 4;
}
else
{
result &= 0x0f;
}
return result;
}
uint8_t VerhoeffChecksum::Multiply(uint8_t aFirst, uint8_t aSecond)
{
static uint8_t kMultiplication[][5] = {{0x01, 0x23, 0x45, 0x67, 0x89}, {0x12, 0x34, 0x06, 0x78, 0x95},
{0x23, 0x40, 0x17, 0x89, 0x56}, {0x34, 0x01, 0x28, 0x95, 0x67},
{0x40, 0x12, 0x39, 0x56, 0x78}, {0x59, 0x87, 0x60, 0x43, 0x21},
{0x65, 0x98, 0x71, 0x04, 0x32}, {0x76, 0x59, 0x82, 0x10, 0x43},
{0x87, 0x65, 0x93, 0x21, 0x04}, {0x98, 0x76, 0x54, 0x32, 0x10}};
return Lookup(aSecond, kMultiplication[aFirst]);
}
uint8_t VerhoeffChecksum::Permute(uint8_t aPosition, uint8_t aValue)
{
static uint8_t kPermutation[][5] = {{0x01, 0x23, 0x45, 0x67, 0x89}, {0x15, 0x76, 0x28, 0x30, 0x94},
{0x58, 0x03, 0x79, 0x61, 0x42}, {0x89, 0x16, 0x04, 0x35, 0x27},
{0x94, 0x53, 0x12, 0x68, 0x70}, {0x42, 0x86, 0x57, 0x39, 0x01},
{0x27, 0x93, 0x80, 0x64, 0x15}, {0x70, 0x46, 0x91, 0x32, 0x58}};
return Lookup(aValue, kPermutation[aPosition]);
}
uint8_t VerhoeffChecksum::InverseOf(uint8_t aValue)
{
static uint8_t kInverse[] = {0x04, 0x32, 0x15, 0x67, 0x89};
return Lookup(aValue, kInverse);
}
Error VerhoeffChecksum::Calculate(const char *aDecimalString, char &aChecksum)
{
Error error;
uint8_t code;
SuccessOrExit(error = ComputeCode(aDecimalString, code, /* aValidate */ false));
aChecksum = static_cast<char>('0' + InverseOf(code));
exit:
return error;
}
Error VerhoeffChecksum::Validate(const char *aDecimalString)
{
Error error;
uint8_t code;
SuccessOrExit(error = ComputeCode(aDecimalString, code, /* aValidate */ true));
VerifyOrExit(code == 0, error = kErrorFailed);
exit:
return error;
}
Error VerhoeffChecksum::ComputeCode(const char *aDecimalString, uint8_t &aCode, bool aValidate)
{
Error error = kErrorNone;
uint8_t code = 0;
uint16_t index = 0;
uint16_t length = StringLength(aDecimalString, kMaxStringLength + 1);
VerifyOrExit(length <= kMaxStringLength, error = kErrorInvalidArgs);
if (!aValidate)
{
length++;
index++;
}
for (; index < length; ++index)
{
char digit = aDecimalString[length - index - 1];
VerifyOrExit(digit >= '0' && digit <= '9', error = kErrorInvalidArgs);
code = Multiply(code, Permute(index % 8, static_cast<uint8_t>(digit - '0')));
}
aCode = code;
exit:
return error;
}
} // namespace Utils
} // namespace ot
#endif // OPENTHREAD_CONFIG_VERHOEFF_CHECKSUM_ENABLE