CheckDigits.Net
3.1.0
dotnet add package CheckDigits.Net --version 3.1.0
NuGet\Install-Package CheckDigits.Net -Version 3.1.0
<PackageReference Include="CheckDigits.Net" Version="3.1.0" />
<PackageVersion Include="CheckDigits.Net" Version="3.1.0" />
<PackageReference Include="CheckDigits.Net" />
paket add CheckDigits.Net --version 3.1.0
#r "nuget: CheckDigits.Net, 3.1.0"
#:package CheckDigits.Net@3.1.0
#addin nuget:?package=CheckDigits.Net&version=3.1.0
#tool nuget:?package=CheckDigits.Net&version=3.1.0
CheckDigits.Net
CheckDigits.Net brings together in one library an extensive collection of different check digit algorithms. CheckDigits.Net has the goal that each algorithm supported be optimized, be resilient to malformed input and that memory allocations be minimized or eliminated completely. Benchmarks for each algorithm are provided to demonstrate performance over a range of values and the memory allocation (if any).
Benchmarks have shown that the optimized versions of the algorithms in CheckDigits.Net are up to 10X-50X faster than those in popular Nuget packages.
Future Algorithms
Is there an algorithm that you would like to see included in CheckDigits.Net? Use the "Contact owners" link on https://www.nuget.org/packages/CheckDigits.Net and let us know. Or contribute to the CheckDigits.Net repository: https://github.com/KnowledgeForwardSolutions/CheckDigits.Net
Table of Contents
- Check Digit Overview
- ISO/IEC 7064 Algorithms
- Supported Algorithms
- Value/Identifier Types and Associated Algorithms
- Using CheckDigits.Net
- Interfaces and Helper Classes
- ICheckDigitAlgorithm
- ISingleCheckDigitAlgorithm
- IDoubleCheckDigitAlgorithm
- IMaskedCheckDigitAlgorithm
- ICheckDigitMask
- Iso7064PureSystemSingleCharacterAlgorithm
- Iso7064PureSystemDoubleCharacterAlgorithm
- Iso7064HybridSystemAlgorithm
- IAlphabet
- ISupplementalCharacterAlphabet
- DammCustomQuasigroupAlgorithm
- IDammQuasigroup
- DammCustomQuasigroup
- Algorithm Descriptions
- ABA RTN (Routing Transit Number) Algorithm
- Alphanumeric MOD 97-10 Algorithm
- CUSIP Algorithm
- Damm Algorithm
- Damm Custom Quasigroup Algorithm
- FIGI (Financial Instrument Global Identifier) Algorithm
- IBAN (International Bank Account Number) Algorithm
- ICAO 9303 Algorithm
- ICAO 9303 Document Size TD1 Algorithm
- ICAO 9303 Document Size TD2 Algorithm
- ICAO 9303 Document Size TD3 Algorithm
- ICAO 9303 Machine Readable Visa Algorithm
- ISAN (International Standard Audiovisual Number) Algorithm
- ISIN (International Securities Identification Number) Algorithm
- ISO 6346 Algorithm
- ISO/IEC 7064 MOD 11,10 Algorithm
- ISO/IEC 7064 MOD 11-2 Algorithm
- ISO/IEC 7064 MOD 1271-36 Algorithm
- ISO/IEC 7064 MOD 27,26 Algorithm
- ISO/IEC 7064 MOD 37-2 Algorithm
- ISO/IEC 7064 MOD 37-36 Algorithm
- ISO/IEC 7064 MOD 661-26 Algorithm
- ISO/IEC 7064 MOD 97-10 Algorithm
- Luhn Algorithm
- Modulus10_1 Algorithm
- Modulus10_2 Algorithm
- Modulus10_13 Algorithm (UPC/EAN/ISBN-13/etc.)
- Modulus11 Algorithm (ISBN-10/ISSN/etc.)
- Modulus11_27Decimal Algorithm
- Modulus11_27Extended Algorithm
- Modulus11Decimal Algorithm (NHS Number/etc.)
- Modulus11Extended Algorithm (ISBN-10/ISSN/etc.)
- NHS (UK National Health Service) Algorithm
- NOID Check Digit Algorithm
- NPI (US National Provider Identifier) Algorithm
- SEDOL Algorithm
- Verhoeff Algorithm
- VIN (Vehicle Identification Number) Algorithm
- Benchmarks
- Release History/Release Notes
Check Digit Overview
Check digits are a useful tool for detecting data transcription errors. By embedding a check digit in a piece of information it is possible to detect common data entry errors early, often before performing more extensive and time consuming processing. A very common example of early error detection is validating a credit card number's check digit in the UI layer while the user is entering the credit card number before attempting to authorize a transaction with the card issuer.
Typical errors that can be detected by check digit algorithms include:
- Single digit transcription errors (any single digit in a value being entered incorrectly).
- Two digit transposition errors (two adjacent digits being swapped, i.e. ab → ba).
- Twin errors (two identical digits being replaced by another pair, i.e. aa → bb).
- Two digit jump transpositions (two digits separated by one position being swapped, i.e. abc → cba).
- Jump twin errors (two identical digits separated by one position being replaced by another pair, i.e. aba → cbc).
Check digit algorithms attempt to balance detection capabilities with the cost in execution time and/or the complexity to implement. While check digits are designed to catch common errors early, they are not foolproof. Statistically, check digit algorithms are subject to "False Positive" results where the check digit appears to be valid, but the value contains a transcription error that the algorithm is not capable of detecting (for example, the Luhn algorithm fails to detect two digit transposition errors with the digits 9 and 0, i.e. 90 → 09 or vice versa). Conversely, check digit algorithms are not subject to "False Negative" results. If a value contains an incorrect check digit, then you can be certain that the value was not transcribed correctly.
ISO/IEC 7064 Algorithms
The ISO/IEC 7064 standard defines a family of algorithms capable of detecting a broad range of errors including all single character transcription errors as well as all or nearly all two character transposition errors, two character jump transposition errors, circular shift errors and double transcription errors (two separate single transcription errors in a single value). The algorithms are suitable for numeric strings, alphabetic strings, alphanumeric strings and can be extended to handle custom character domains beyond ASCII alphanumeric characters.
ISO/IEC 7064 algorithms fall into different categories. Pure system algorithms use a single modulus value and a radix value and can generate one or two check characters, depending on the algorithm. If a pure system algorithm generates a single check character, the check character produced will either be one of the valid input characters or a single supplementary character that is only valid as a check digit. Hybrid system algorithms use two modulus values, M and M+1, and generate a single check character that will be one of the valid input characters.
While CheckDigits.Net provides optimized implementations of all of the algorithms defined in the ISO/IEC 7064 standard, the standard is flexible enough to support the creation of algorithms for custom alphabets. For example, Annex B of the ISO/IEC 7064 standard demonstrates the creation of a system for the Danish alphabet which includes three additional characters. See the section on Interfaces and Helper Classes for more information about how to create custom algorithms for custom alphabets.
The ISO/IEC 7064:2003 standard is available at https://www.iso.org/standard/31531.html
Supported Algorithms
- ABA RTN (Routing Transit Number) Algorithm
- Alphanumeric MOD 97-10 Algorithm
- CUSIP Algorithm
- Damm Algorithm
- Damm Custom Quasigroup Algorithm
- FIGI (Financial Instrument Global Identifier) Algorithm
- IBAN (International Bank Account Number) Algorithm
- ICAO 9303 Algorithm
- ICAO 9303 Document Size TD1 Algorithm
- ICAO 9303 Document Size TD2 Algorithm
- ICAO 9303 Document Size TD3 Algorithm
- ICAO 9303 Machine Readable Visa Algorithm
- ISAN (International Standard Audiovisual Number) Algorithm
- ISIN (International Securities Identification Number) Algorithm
- ISO 6346 Algorithm
- ISO/IEC 7064 MOD 11,10 Algorithm
- ISO/IEC 7064 MOD 11-2 Algorithm
- ISO/IEC 7064 MOD 1271-36 Algorithm
- ISO/IEC 7064 MOD 27,26 Algorithm
- ISO/IEC 7064 MOD 37-2 Algorithm
- ISO/IEC 7064 MOD 37-36 Algorithm
- ISO/IEC 7064 MOD 661-26 Algorithm
- ISO/IEC 7064 MOD 97-10 Algorithm
- Luhn Algorithm
- Modulus10_1 Algorithm
- Modulus10_2 Algorithm
- Modulus10_13 Algorithm (UPC/EAN/ISBN-13/etc.)
- Modulus11 Algorithm (ISBN-10/ISSN/etc.)
- Modulus11_27Decimal Algorithm
- Modulus11_27Extended Algorithm
- Modulus11Decimal Algorithm (NHS Number/etc.)
- Modulus11Extended Algorithm (ISBN-10/ISSN/etc.)
- NHS (UK National Health Service) Algorithm
- NOID Check Digit Algorithm
- NPI (US National Provider Identifier) Algorithm
- SEDOL Algorithm
- Verhoeff Algorithm
- VIN (Vehicle Identification Number) Algorithm
Value/Identifier Types and Associated Algorithms
Using CheckDigits.Net
Add a reference to CheckDigits.Net to your project.
Obtain an instance of the desired check digit algorithm. Either create an instance
by using new AlgorithmXyz() or using the static Algorithms class to
get a lazily instantiated singleton instance of the desired algorithm.
Calculate a check digit for a value by invoking the TryCalculateCheckDigit method.
Validate a value that contains a check digit by invoking the Validate method.
Examples:
using CheckDigits.Net;
// Create a new instance of the Luhn algorithm.
var algorithm = new LuhnAlgorithm();
// Get a lazily instantiated singleton instance of the Luhn algorithm.
var lazy = Algorithms.Luhn;
// Calculate the check digit for a value that does not already contain a check digit.
var newValue = "123456789012345";
var successful = algorithm.TryCalculateCheckDigit(newValue, out var checkDigit); // Returns true; checkDigit will equal '2'
// Validate a value that contains a check digit.
var toValidate = "1234567890123452";
var isValid = lazy.Validate(toValidate); // Returns true
Interfaces and Helper Classes
ICheckDigitAlgorithm
Every algorithm in CheckDigits.Net implements the ICheckDigitAlgorithm interface
which defines the following members:
String AlgorithmDescription { get; }- Gets a description of the algorithm.String AlgorithmName { get; }- Gets the name of the algorithm.Boolean Validate(String value)- Validates a value that contains a check digit.
The Validate method will return true if the value contains a valid check digit according to the algorithm and false otherwise. Mal-formed input such as a null value, an empty string, a string of incorrect length or a string that contains characters that are not valid for the algorithm will return false instead of throwing an exception.
ISingleCheckDigitAlgorithm
Algorithms that use a single character check digit can also implement the
ISingleCheckDigitAlgorithm interface which defines the following member in
addition to those defined in ICheckDigitAlgorithm:
Boolean TryCalculateCheckDigit(String value, out Char checkDigit)- Calculates the check digit for a value that does not already contain a check digit.
The TryCalculateCheckDigit method will return true if the check digit was successfully calculated and false otherwise. If the method returns true, the out parameter will contain the calculated check digit. If the method returns false, the out parameter will contain '\0'. Mal-formed input such as a null value, an empty string, a string of incorrect length or a string that contains characters that are not valid for the algorithm will return false instead of throwing an exception.
ISingleCheckDigitAlgorithm is not implemented for algorithms for government
issued identifiers (for example, UK NHS numbers and US NPI numbers) or values
issued by a single authority (such as ABA Routing Transit Numbers).
IDoubleCheckDigitAlgorithm
Algorithms that use two character check digits can also implement the
IDoubleCheckDigitAlgorithm interface which defines the following member in
addition to those defined in ICheckDigitAlgorithm:
Boolean TryCalculateCheckDigits(String value, out Char firstCheckDigit, out Char secondCheckDigit)- Calculates the two check digits for a value that does not already contain check digits.
The TryCalculateCheckDigits method will return true if the check digit was successfully calculated and false otherwise. If the method returns true, the out parameters will contain the calculated check digits. If the method returns false, the out parameters will contain '\0'. Mal-formed input such as a null value, an empty string, a string of incorrect length or a string that contains characters that are not valid for the algorithm will return false instead of throwing an exception.
IDoubleCheckDigitAlgorithm is not implemented for algorithms for government
issued identifiers (for example, UK NHS numbers and US NPI numbers) or values
issued by a single authority (such as ABA Routing Transit Numbers).
IMaskedCheckDigitAlgorithm
Algorithms that implement the IMaskedCheckDigitAlgorithm interface support an
overload of the Validate method that accepts an ICheckDigitMask instance that
is used to filter characters from the value being checked. Currently the
following algorithms implement IMaskedCheckDigitAlgorithm:
- Alphanumeric MOD 97-10 Algorithm
- Damm Algorithm
- Damm Custom Quasigroup Algorithm
- Luhn Algorithm
- Modulus10_1 Algorithm
- Modulus10_13 Algorithm
- Modulus10_2 Algorithm
- Modulus11_27Decimal Algorithm
- Modulus11_27Extended Algorithm
- Modulus11Decimal Algorithm
- Modulus11Extended Algorithm
- Verhoeff Algorithm
ICheckDigitMask
To support filtering characters from the value being checked, CheckDigits.Net
defines the ICheckDigitMask interface which has the following members:
Boolean IncludeCharacter(Int32 index)- Returns true if the character at the specified zero based index should be included when calculating the check digit.Boolean ExcludeCharacter(Int32 index)- Returns true if the character at the specified zero based index should be excluded when calculating the check digit.
Here are example implementations of ICheckDigitMask:
// Excludes every 5th character, allowing for spaces or dashes in credit card numbers.
public class CreditCardMask : ICheckDigitMask
{
public Boolean ExcludeCharacter(Int32 index) => (index + 1) % 5 == 0;
public Boolean IncludeCharacter(Int32 index) => (index + 1) % 5 != 0;
}
// Excludes the 4th and 8th characters from Canadian Social Insurance Numbers which breaks the SIN into groups of three digits.
public class CaSocialInsuranceNumberMask : ICheckDigitMask
{
public Boolean ExcludeCharacter(Int32 index) => index == 3 || index == 7;
public Boolean IncludeCharacter(Int32 index) => index != 3 && index != 7;
}
Iso7064PureSystemSingleCharacterAlgorithm
If you want to use an ISO 7064 algorithm that uses a modulus and radix and a
single check digit, but you require a custom alphabet, then you can use the
Iso7064PureSystemSingleCharacterAlgorithm class. Note that ISO 7064 pure system
algorithms that generate a single check character can generate a check character
that is either one of the valid input characters or a single supplementary
character that is only valid as a check digit. To use Iso7064PureSystemSingleCharacterAlgorithm
you must first create an instance of a class that implements
ISupplementalCharacterAlphabet to define your
custom alphabet. You then create an instance of
Iso7064PureSystemSingleCharacterAlgorithm by supplying the algorithm name,
algorithm description, modulus, radix and the custom alphabet instance to the
class constructor. Iso7064PureSystemSingleCharacterAlgorithm implements the
ISingleCheckDigitAlgorithm interface so you can
use the TryCalculateCheckDigit method to calculate the check digit for values
that use the custom alphabet and the Validate method to validate values that
contain a check digit.
Iso7064PureSystemDoubleCharacterAlgorithm
If you want to use an ISO 7064 algorithm that uses a modulus and radix and
generates two check characters, but you require a custom alphabet, then you can
use the Iso7064PureSystemDoubleCharacterAlgorithm class. Since ISO 7064 pure
system algorithms that generate two check characters will only generate check
characters that are valid input characters, so you only need to create an
instance of a class that implements IAlphabet to define your custom
alphabet. You then create an instance of Iso7064PureSystemDoubleCharacterAlgorithm
by supplying the algorithm name, algorithm description, modulus, radix and the
custom alphabet instance to the class constructor. Iso7064PureSystemDoubleCharacterAlgorithm
implements the IDoubleCheckDigitAlgorithm interface
so you can use the TryCalculateCheckDigits method to calculate the check digits
for values that use the custom alphabet and the Validate method to validate values
that contain check digits.
Iso7064HybridSystemAlgorithm
If you want to use an ISO 7064 algorithm that uses two modulus values (M and M+1)
and generates a single check digit, but you require a custom alphabet, then you
can use the Iso7064HybridSystemAlgorithm class. ISO 7064 hybrid system algorithms
that generate a single check character will only generate check characters that
are valid input characters, so you only need to create an instance of a class
that implements IAlphabet to define your custom alphabet. You then
create an instance of Iso7064HybridSystemAlgorithm by supplying the algorithm
name, algorithm description, modulus M and the custom alphabet instance to the
class constructor. Iso7064HybridSystemAlgorithm implements the
ISingleCheckDigitAlgorithm interface so you can
use the TryCalculateCheckDigit method to calculate the check digit for values
that use the custom alphabet and the Validate method to validate values that
contain a check digit.
IAlphabet
Use the IAlphabet interface to define a custom alphabet for ISO 7064 algorithms
that generate check characters that are valid input characters. IAlphabet defines
the following methods for mapping characters to their integer equivalents and vice versa:
Int32 CharacterToInteger(Char ch)- Maps a character in the value being processed to its integer equivalent. A value less than zero indicates an invalid character.Char IntegerToCheckCharacter(Int32 value)- Maps a calculated check digit to its character equivalent.
The ISO/IEC 7064 standard includes an example of a custom alphabet for the
Danish alphabet which includes three additional characters in Annex B of the
standard. Here is an implementation of that example using the IAlphabet
interface to create an instance of 'Iso7064PureSystemDoubleCharacterAlgorithm'
with the custom Danish alphabet. The Annex B example uses modulus = 29 and
radix = 2, so the algorithm will generate two check characters and the valid
input characters will be mapped to the integer values 0-28.
public class DanishAlphabet : IAlphabet
{
// Additional characters:
// diphthong AE (\u00C6) has value 26
// slashed O (\u00D8) has value 27
// A with diaeresis (\u00C4) has value 28
private const String _validCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\u00C6\u00D8\u00C4";
public Int32 CharacterToInteger(Char ch)
=> ch switch
{
var x when x >= 'A' && x <= 'Z' => x - 'A',
'\u00C6' => 26,
'\u00D8' => 27,
'\u00C4' => 28,
_ => -1
};
public Char IntegerToCheckCharacter(Int32 checkDigit) => _validCharacters[checkDigit];
}
var checkAlgorithm = new Iso7064PureSystemDoubleCharacterAlgorithm(
"Danish",
"Danish, modulus = 29, radix = 2",
29,
2,
new DanishAlphabet());
// Calculate the check digit for Danish word for sister (uses slashed O instead of i)
var str = "S\u00D8STER";
var successful = checkAlgorithm.TryCalculateCheckDigits(str, out var firstChar, out var secondChar); // Returns true, firstChar = 'D', secondChar = 'A'
// Validate a value containing check digit(s).
var isValid = checkAlgorithm.Validate("S\u00D8STERDA"); // Returns true
ISupplementalCharacterAlphabet
Use the ISupplementalCharacterAlphabet interface to define a custom alphabet
for ISO 7064 algorithms that generate a single check character that can be either
a valid input character or a single supplementary character that is only valid
as a check digit. ISupplementalCharacterAlphabet extends the IAlphabet
interface by adding the following method:
Int32 CheckCharacterToInteger(Char ch)- Maps a check character to its integer equivalent. A value less than zero indicates an invalid character.
DammCustomQuasigroupAlgorithm
To use the Damm algorithm for values other than numeric strings, you can use the
DammCustomQuasigroupAlgorithm class. You define the set of valid characters
and the quasigroup required by the algorithm by implementing the IDammQuasigroup
interface. You then create an instance of DammCustomQuasigroupAlgorithm by
supplying an instance of your IDammQuasigroup implementation to the class
constructor. DammCustomQuasigroupAlgorithm implements the
ISingleCheckDigitAlgorithm interface so you can
use the TryCalculateCheckDigit method to calculate the check digit for values
that use the custom alphabet and the Validate method to validate values that
contain a check digit.
IDammQuasigroup
The IDammQuasigroup interface is used to define a custom quasigroup table for
the Damm Custom Quasigroup Algorithm. The
interface defines the following members:
Int32 MapCharacter(Char ch)- Maps a character to its equivalent integer value in the quasigroup. A value less than zero or greater than or equal to the order of the quasigroup indicates an invalid character.Char GetCheckCharacter(Int32 value)- Retrieves the check character for a particular integer value in the quasigroup.Int32 this[Int32 row, Int32 column] { get; }- An indexer for retrieving the quasigroup value for a particular pair of integer values.Int32 Order { get; }- Gets the order of the quasigroup, which is the number of valid characters in the quasigroup.
This is an example implementation of IDammQuasigroup: which defines the standard
Damm quasigroup specified on page 111 of Damm's doctoral dissertation.
// Note that the indexer performs no bounds checking because the DammCustomQuasigroupAlgorithm
// ensures that the values passed to the indexer are valid for the quasigroup.
// For the MapCharacter function, a value less than zero or >= Order will be treated
// as an invalid character by the DammCustomQuasigroupAlgorithm and will cause the
// algorithm to return false when validating or calculating check digits.
public class DammQuasigroupOrder10 : IDammQuasigroup
{
private static readonly Int32[,] _quasigroupTable =
{
{ 0, 3, 1, 7, 5, 9, 8, 6, 4, 2, },
{ 7, 0, 9, 2, 1, 5, 4, 8, 6, 3, },
{ 4, 2, 0, 6, 8, 7, 1, 3, 5, 9, },
{ 1, 7, 5, 0, 9, 8, 3, 4, 2, 6, },
{ 6, 1, 2, 3, 0, 4, 5, 9, 7, 8, },
{ 3, 6, 7, 4, 2, 0, 9, 5, 8, 1, },
{ 5, 8, 6, 9, 7, 2, 0, 1, 3, 4, },
{ 8, 9, 4, 5, 3, 6, 2, 0, 1, 7, },
{ 9, 4, 3, 8, 6, 1, 7, 2, 0, 5, },
{ 2, 5, 8, 1, 4, 3, 6, 7, 9, 0, },
};
public Int32 this[Int32 interim, Int32 next] => _quasigroupTable[interim, next];
public Int32 Order => 10;
public Char GetCheckCharacter(Int32 interim) => (Char)('0' + interim);
public Int32 MapCharacter(Char ch) => ch - '0';
DammCustomQuasigroup
Instead of creating your own implementation of IDammQuasigroup,
you can create an instance of the DammCustomQuasigroup class which implements the
IDammQuasigroup interface. To create an instance of DammCustomQuasigroup, you
define the quasigroup table as a two dimensional array of integers or characters
and supply the appropriate mapping functions for characters to integer values and
integer values to check characters. The DammCustomQuasigroup class will flatten
the two dimensional array into a one dimensional array to optimize the indexer for
retrieving quasigroup values. This takes advantage of .Net's optimization for
single dimensional arrays and provides for up to a 30% improvement in performance
for the indexer compared to a two dimensional array.
DammCustomQuasigroup has the following requirements for the supplied two
dimensional array of integers or characters:
- The array may not be null and must have a length greater than zero.
- The array must be order 2 (i.e. a minimum of 2 rows and 2 columns).
- The array must be square (i.e. the number of rows must equal the number of columns).
- The array must have a zero diagonal (i.e. all values where the row index equals the column index must have an integer value zero).
- The integer values in the array must be greater than or equal to zero and less than the order of the quasigroup (i.e. the number of rows/columns)
- The array must be a Latin square (i.e. each integer value must occur exactly once in each row and exactly once in each column).
If using a two dimensional array of characters instead of integers, the constructor
will use the supplied MapCharacter function to create the internal integer quasigroup
table from the supplied character quasigroup table.
Here is an example of creating a DammCustomQuasigroup using a two dimensional
array of characters and mapping functions for a hexadecimal quasigroup.
// Hexadecimal quasigroup. The character set for the quasigroup is 0-9 and A-F
// where A=10, B=11, C=12, D=13, E=14 and F=15.
public static Int32 MapCharacter(Char ch) => ch switch
{
var d when ch >= '0' && ch <= '9' => d - '0',
var c when ch >= 'A' && ch <= 'F' => c - 'A' + 10,
_ => -1
};
public static Char GetCheckCharacter(Int32 interim) => interim switch
{
var d when interim >= 0 && interim <= 9 => (Char)('0' + interim),
var c when interim >= 10 && interim <= 15 => (Char)('A' + c - 10),
_ => '\0'
};
// Note that this quasigroup uses a simple shift pattern for the values.
// It is only being used as an example of how to create a custom quasigroup and
// you should not use this quasigroup for production purposes without first analyzing
// the error detection capabilities of the quasigroup for your particular use case.
var hexQuasigroup = new DammCustomQuasigroup(
new Char[,]
{
{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' },
{ 'F', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E' },
{ 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D' },
{ 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C' },
{ 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B' },
{ 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A' },
{ 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' },
{ '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7', '8' },
{ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7' },
{ '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6' },
{ '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5' },
{ '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4' },
{ '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3' },
{ '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2' },
{ '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1' },
{ '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0' },
},
MapCharacter,
GetCheckCharacter);
Algorithm Descriptions
ABA RTN Algorithm
Description
The American Bankers Association (ABA) Routing Transit Number (RTN) algorithm is a modulus 10 algorithm that uses weights 3, 7 and 1. The algorithm can detect all single digit transcription errors and most two digit transposition errors except those where the transposed digits differ by 5 (i.e. 1 ↔ 6, 2 ↔ 7, etc.).
The ABA RTN algorithm only supports validation of check digits and does not support calculation of check digits.
Details
- Valid characters - decimal digits ('0' - '9')
- Check digit size - one character
- Check digit value - decimal digit ('0' - '9')
- Check digit location - ninth digit
- Value length - 9 characters
- Class name -
AbaRtnAlgorithm
Links
Wikipedia: https://en.wikipedia.org/wiki/ABA_routing_transit_number#Check_digit
Alphanumeric MOD 97-10 Algorithm
Description
The Alphanumeric MOD 97-10 algorithm uses a variation of the ISO/IEC 7064 MOD 97-10 algorithm where alphabetic characters (A-Z) are mapped to integers (10-35) before calculating the check digit. The algorithm is case insensitive and lowercase letters are mapped to their uppercase equivalent before conversion to integers.
AlphanumericMod97_10Algorithm implements IMaskedCheckDigitAlgorithm and can be used
to validate values that are formatted with non-check digit characters (for example,
a value formatted with spaces or dashes for human readability).
Details
- Valid characters - alphanumeric characters ('0' - '9', 'A' - 'Z')
- Check digit size - two characters
- Check digit value - decimal digits ('0' - '9')
- Check digit location - assumed to be the trailing (right-most) characters when validating
- Class name -
AlphanumericMod97_10Algorithm
Common Applications
- Legal Entity Identifier (LEI)
- Universal Loan Identifier (ULI)
Links
Wikipedia: https://en.wikipedia.org/wiki/Legal_Entity_Identifier
CUSIP Algorithm
Description
The CUSIP (Committee on Uniform Security Identification Procedures) algorithm is used for nine character alphanumeric codes that identify North American financial securities. The algorithm has similarities with both the Luhn algorithm and the ISIN algorithm.
The CUSIP algorithm only supports validation of check digits and does not support calculation of check digits.
Details
- Valid characters - alphanumeric characters ('0' - '9', 'A' - 'Z') plus '*', '@' and '#'
- Check digit size - one character
- Check digit value - decimal digit ('0' - '9')
- Check digit location - assumed to be the trailing (right-most) character when validating
- Class name -
CusipAlgorithm
Links
Wikipedia: https://en.wikipedia.org/wiki/CUSIP
Damm Algorithm
Description
The Damm algorithm was first described by H. Michael Damm in 2004. It is similar to the Verhoeff algorithm in that it can detect all single digit transcription errors and all two digit transposition errors and that it uses a precomputed table instead of modulus operations to calculate the check digit. Unlike the Verhoeff algorithm, the Damm algorithm uses a single quasigroup table of order 10 instead of the multiple tables used by Verhoeff. The implementation of the Damm algorithm provided by CheckDigits.Net uses the table generated from the quasigroup specified on page 111 of Damm's doctoral dissertation.
DammAlgorithm implements IMaskedCheckDigitAlgorithm and can be used
to validate values that are formatted with non-check digit characters (for example,
a value formatted with spaces or dashes for human readability).
Details
- Valid characters - decimal digits ('0' - '9')
- Check digit size - one character
- Check digit value - decimal digit ('0' - '9')
- Check digit location - assumed to be the trailing (right-most) character when validating
- Class name -
DammAlgorithm
Damm Custom Quasigroup Algorithm
Description
The Damm Custom Quasigroup algorithm is a generalization of CheckDigits.Net's
basic Damm algorithm implementation. As the name suggests, it allows
for the use of custom quasigroups of different orders, enabling the calculation
of check digits for a wider range of input values. To use the Damm Custom Quasigroup algorithm,
you must create an object that implements the IDammQuasigroup
interface, providing a custom quasigroup table and then supply that object to
the constructor of the DammCustomQuasigroupAlgorithm class. You can also use the
helper DammCustomQuasigroup class to create an instance
of IDammQuasigroup.
Note: For values consisting of decimal digits, the standard DammAlgorithm is the
recommended option since the quasigroup used by the standard Damm algorithm has been
shown to have good error detection capabilities for decimal digit strings and since
the DammAlgorithm class is optimized for that particular quasigroup.
Note that the error detection capabilities of the Damm Custom Quasigroup algorithm will depend on the properties of the custom quasigroup provided. Generation of quasigroups with good error detection capabilities is a non-trivial task, but with the advent of AI tools, it is easier than before. However it is important to thoroughly test the error detection capabilities of any custom quasigroup used in production.
It is also important to note that there are many different quasigroups of any particular order that can be used with the Damm algorithm and that the particular quasigroup used to create a check character must also be used to validate that check character. This means that you must clearly document the quasigroup used for a particular value and ensure that the same quasigroup is used for validation, especially if the organization issuing the values is different from the organization validating the values.
DammCustomQuasigroupAlgorithm implements IMaskedCheckDigitAlgorithm and can be used
to validate values that are formatted with non-check digit characters (for example,
a value formatted with spaces or dashes for human readability).
Details
- Valid characters - depends on the custom quasigroup
- Check digit size - one character
- Check digit value - depends on the custom quasigroup, but will be a character that is valid for the quasigroup
- Check digit location - assumed to be the trailing (right-most) character when validating
- Class name -
DammCustomQuasigroupAlgorithm
Links
Wikipedia: https://en.wikipedia.org/wiki/Damm_algorithm
See also: Damm Algorithm for the standard implementation for decimal digits
FIGI Algorithm
Description
The FIGI (Financial Instrument Global Identifier) algorithm is used for 12 character values issued by Bloomberg L.P. that are used to identify a variety of financial instruments including common stock, futures, derivatives, bonds and more. The algorithm is a variation of the Luhn algorithm and has the same weaknesses as the Luhn algorithm with digit characters. But like the ISIN algorithm (which also extends the Luhn algorithm to support alphanumeric strings), the FIGI algorithm has additional weaknesses when detecting errors involving alphabetic characters. Each alphabetic character has a digit character and at least one other alphabetic character that can be freely substituted for that character and which will result in the same check digit being calculated. This means that single character transcription errors involving those characters can not be detected by the algorithm.
The FIGI algorithm only supports validation of check digits and does not support calculation of check digits.
Details
- Valid characters - decimal digits ('0' - '9') and upper case consonants ('BCDFGHJKLMNPQRSTVWXYZ')
- Check digit size - one character
- Check digit value - decimal digits ('0' - '9')
- Check digit location - character position 12 (1-based)
- Value length - 12
- Class name -
FigiAlgorithm
Links
https://en.wikipedia.org/wiki/Financial_Instrument_Global_Identifier https://www.openfigi.com/assets/content/figi-check-digit-2173341b2d.pdf
IBAN Algorithm
Description
The IBAN (International Bank Account Number) algorithm uses a variation of the ISO/IEC 7064 MOD 97-10 algorithm where alphabetic characters (A-Z) are mapped to integers (10-35) before calculating the check digit. Additionally, the first four characters (2 character country code and 2 decimal check digits) are moved to the end of the string before calculating the check digit.
Note that this implementation only confirms that the length of the value is sufficient to calculate the check digits (min length = 5) and that check digit characters in positions 3 & 4 are valid for the string. All other IBAN checks (the leading two characters indicating a valid country code, the check digit positions only contain digits, maximum length, country specific check digits contained in account number, etc.) are left to the application developer.
Details
- Valid characters - alphanumeric characters ('0' - '9', 'A' - 'Z')
- Check digit size - two characters
- Check digit value - decimal digits ('0' - '9')
- Check digit location - character positions 3 & 4 (1-based) when validating
- Value minimum length - 5
- Class name -
IbanAlgorithm
Links
Wikipedia: https://en.wikipedia.org/wiki/International_Bank_Account_Number
ICAO 9303 Algorithm
Description
The ICAO 9303 (International Civil Aviation Organization) algorithm is a modulus 10 algorithm used in the field of MRTODTs (Machine Readable Official Travel Documents). The algorithm uses weights 7, 3, and 1 with the weights applied starting from the left most character.
The algorithm can not detect single character transcription errors where the difference between the correct character and the incorrect character is 10, i.e. 0 → A, B->L, and vice versa. Nor can the algorithm detect two character transposition errors where the difference between the transposed characters is a multiple of 5, i.e. 27 ↔ 72, D8 ↔ 8D, BL ↔ LB).
Details
- Valid characters - decimal digits ('0' - '9'), upper case letters ('A' - 'Z') and a filler character ('<').
- Check digit size - one character
- Check digit value - decimal digit ('0' - '9')
- Check digit location - assumed to be the trailing (right-most) character when validating
- Class name -
Icao9303Algorithm
Links
https://en.wikipedia.org/wiki/Machine-readable_passport#Official_travel_documents https://www.icao.int/publications/Documents/9303_p3_cons_en.pdf
ICAO 9303 Document Size TD1 Algorithm
The ICAO 9303 (International Civil Aviation Organization) specification for Machine Readable Travel Documents Size TD1 uses multiple check digits in the machine readable zone of the document. The first line of the machine readable zone contains a field for the document number (including a possible extended document number) and associated check digit. The second line of the machine readable zone contains fields for date of birth, date of expiry and associated check digits for each field. The individual field check digits and the composite check digit are all calculated using the ICAO 9303 Algorithm.
The machine readable zone of a Size TD1 document consists of three lines of 30
characters. The value passed to the Validate method should contain all lines of
data concatenated together. You may optionally use line separator characters in
the concatenated value, either the Windows line separator (a carriage return
character followed by a line feed character - '\r\n') or the Unix line separator
(a line feed character - '\n'). The ICAO 9303 Document Size TD1 algorithm will
determine the line separator used from the length the value passed to the Validate
method - 90 characters for no line separators, 94 characters for Windows line
separators and 92 characters for Unix line separators. If the length of the value
does not match one of these lengths then the Validate method will return false.
The ICAO 9303 Document Size TD1 Algorithm will validate the check digits of the
three fields (document number, date of birth and date of expiry) as well as the
composite check digit. If any of the check digits fail validation then the
Validate method will return false.
The ICAO 9303 Document Size TD1 algorithm only supports validation of check digits and does not support calculation of check digits.
Details
- Valid characters -
- decimal digits ('0' - '9'), upper case letters ('A' - 'Z') and a filler character ('<') for document number/extended document number field
- decimal digits ('0' - '9') and a filler character ('<') for date of birth and date of expiry fields
- Check digit size - one character
- Check digit value - decimal digit ('0' - '9')
- Check digit location - trailing (right-most) character of individual fields, trailing character of second line for composite check digit
- Value length - three lines of 30 characters plus additional line separator characters as specified by the LineSeparator property
- Class name -
Icao9303SizeTD1Algorithm
Links
https://www.icao.int/publications/Documents/9303_p5_cons_en.pdf
ICAO 9303 Document Size TD2 Algorithm
Description
The ICAO 9303 (International Civil Aviation Organization) specification for Machine Readable Travel Documents Size TD2 uses multiple check digits in the machine readable zone of the document. The second line of the machine readable zone contains fields for document number (including a possible extended document number), date of birth and date of expiry and associated check digits for each field. The individual field check digits and the composite check digit are all calculated using the ICAO 9303 Algorithm.
The machine readable zone of a Size TD2 document consists of two lines of 36
characters. The value passed to the Validate method should contain all lines of
data concatenated together. You may optionally use line separator characters in
the concatenated value, either the Windows line separator (a carriage return
character followed by a line feed character - '\r\n') or the Unix line separator
(a line feed character - '\n'). The ICAO 9303 Document Size TD2 algorithm will
determine the line separator used from the length the value passed to the Validate
method - 72 characters for no line separators, 74 characters for Windows line
separators and 73 characters for Unix line separators. If the length of the value
does not match one of these lengths then the Validate method will return false.
The ICAO 9303 Document Size TD2 Algorithm will validate the check digits of the
three fields (document number, date of birth and date of expiry) as well as the
composite check digit. If any of the check digits fail validation then the
Validate method will return false.
The ICAO 9303 Document Size TD2 algorithm only supports validation of check digits and does not support calculation of check digits.
Details
- Valid characters -
- decimal digits ('0' - '9'), upper case letters ('A' - 'Z') and a filler character ('<') for document number/extended document number field
- decimal digits ('0' - '9') and a filler character ('<') for date of birth and date of expiry fields
- Check digit size - one character
- Check digit value - decimal digit ('0' - '9')
- Check digit location - trailing (right-most) character of individual fields, trailing character of second line for composite check digit
- Value length - two lines of 36 characters plus additional line separator characters as specified by the LineSeparator property
- Class name -
Icao9303SizeTD2Algorithm
Links
https://www.icao.int/publications/Documents/9303_p6_cons_en.pdf
ICAO 9303 Document Size TD3 Algorithm
Description
The ICAO 9303 (International Civil Aviation Organization) specification for Machine Readable Passports and other Size TD3 travel documents uses multiple check digits in the machine readable zone of the document. The second line of the machine readable zone contains fields for passport number, date of birth, date of expiry and an optional personal number field with each field having a check digit calculated using the ICAO 9303 Algorithm. In addition, the machine readable zone contains a final composite check digit calculated for all four of the above fields and their check digits. The composite check digit is also calculated using the ICAO 9303 Algorithm.
The machine readable zone of a Size TD3 document consists of two lines of 44
characters. The value passed to the Validate method should contain both lines of
data concatenated together. You may optionally use line separator characters in
the concatenated value, either the Windows line separator (a carriage return
character followed by a line feed character - '\r\n') or the Unix line separator
(a line feed character - '\n'). The ICAO 9303 Document Size TD3 algorithm will
determine the line separator used from the length the value passed to the Validate
method - 88 characters for no line separators, 90 characters for Windows line
separators and 89 characters for Unix line separators. If the length of the value
does not match one of these lengths then the Validate method will return false.
The ICAO 9303 Document Size TD3 Algorithm will validate the check digits of the
four fields (passport number, date of birth, date of expiry and optional personal
number) as well as the composite check digit. If any of the check digits fail
validation then the Validate method will return false.
The ICAO 9303 Document Size TD3 algorithm only supports validation of check digits and does not support calculation of check digits.
Details
- Valid characters -
- decimal digits ('0' - '9'), upper case letters ('A' - 'Z') and a filler character ('<') for document number/extended document number field
- decimal digits ('0' - '9') and a filler character ('<') for date of birth and date of expiry fields
- Check digit size - one character
- Check digit value - decimal digit ('0' - '9')
- Check digit location - trailing (right-most) character of individual fields, trailing character of entire string for composite check digit
- Value length - two lines of 44 characters plus additional line separator characters as specified by the LineSeparator property
- Class name -
Icao9303SizeTD3Algorithm
Links
https://www.icao.int/publications/Documents/9303_p4_cons_en.pdf
ICAO 9303 Machine Readable Visa Algorithm
Description
The ICAO 9303 (International Civil Aviation Organization) specification for Machine Readable Visas uses multiple check digits in the machine readable zone of the document. The second line of the machine readable zone contains fields for document number, date of birth and date of expiry and associated check digits for each field. (Unlike other ICAO 9303 TD1, TD2 or TD3 documents, no composite check digit is used.) The individual field check digits are all calculated using the ICAO 9303 Algorithm.
Machine Readable Visas have two formats: MRV-A and MRV-B. The MRV-A format uses two lines of 44 characters while the MRV-B format uses two lines of 36 characters. The individual fields in the second line of the machine readable zone are located in the same character positions regardless of the format. The Validate method can validate either format and the algorithm will determine the format from the length of the value passed to the Validate method.
The machine readable zone of a Machine Readable Visa consists of two lines of 36
characters. The value passed to the Validate method should contain all lines of
data concatenated together. You may optionally use line separator characters in
the concatenated value, either the Windows line separator (a carriage return
character followed by a line feed character - '\r\n') or the Unix line separator
(a line feed character - '\n'). The ICAO 9303 Machine Readable Visa algorithm will
determine the line separator used from the length the value passed to the Validate
method - 88 characters (MRV-A) or 72 characters (MRV-B) for no line separators,
90 characters (MRV-A) or 74 characters (MRV-B) for Windows line separators and
89 characters (MRV-A) or 73 characters (MRV-B) for Unix line separators. If the
length of the value does not match one of these lengths then the Validate method
will return false.
The ICAO 9303 Machine Readable Visa Algorithm will validate the check digits of
the three fields (document number, date of birth and date of expiry). If any of
the check digits fail validation then the Validate method will return false.
In addition, if the value is not the correct length (two lines of either 44 or
36 characters, plus line separator characters matching the LineSeparator
property) then the method will return false.
The ICAO 9303 Machine Readable Visa algorithm only supports validation of check digits and does not support calculation of check digits.
Details
- Valid characters -
- decimal digits ('0' - '9'), upper case letters ('A' - 'Z') and a filler character ('<') for document number/extended document number field
- decimal digits ('0' - '9') and a filler character ('<') for date of birth and date of expiry fields
- Check digit size - one character
- Check digit value - decimal digit ('0' - '9')
- Check digit location - trailing (right-most) character of individual fields
- Value length - two lines of either 44 characters (MRV-A) or 36 characters (MRV-B), plus additional line separator characters as specified by the LineSeparator property
- Class name -
Icao9303MachineReadableVisaAlgorithm
Links
https://www.icao.int/publications/Documents/9303_p7_cons_en.pdf
ISAN Algorithm
Description
The ISAN (International Standard Audiovisual Number) algorithm uses a variation of the ISO/IEC 7064 MOD 37,36 algorithm and can have either one or two check characters. A full ISAN value consists of 12 hexadecimal digits for the "root" segment, 4 hexadecimal digits for the "episode" segment, an alphanumeric check character calculated for the 16 characters of the root/episode segments and optionally, 8 hexadecimal digits for the version segment and an alphanumeric check character calculated for the 24 characters of the root/episode/version segments. Per https://www.isan.org/docs/isan_check_digit_calculation_v2.0.pdf, both check characters must be correct if the value includes a version segment.
CheckDigits.Net can validate either unformatted ISAN values consisting only of hexadecimal digits and alphanumeric check characters or ISAN values that have been formatted for human readability.
To validate unformatted root+version ISAN values, use the Validate method. The Validate method only checks 26 character unformatted ISAN root+version values. (To check 17 character root/episode only ISAN values, use the ISO/IEC 7064 MOD 37,36 algorithm directly.)
To validate formatted ISAN values, either root/episode values or root/episode/version values, use the ValidateFormatted method. The ValidateFormatted method will check both the format of the value ("ISAN " prefix plus dash characters that separate the value into 4 character groups) and the check character(s) in the value.
An example formatted root/episode ISAN value is ISAN 0000-0000-C36D-002B-K. An example formatted root/episode/version ISAN value is ISAN 0000-0000-C36D-002B-K-0000-0000-E.
Details
- Valid characters - hexadecimal characters ('0' - '9', 'A' - 'F')
- Check digit size - one character
- Check digit value - alphanumeric characters ('0' - '9', 'A' - 'Z')
- Check digit location - the 17th non-format character (and the 26th non-format character for root+version values)
- Class name -
IsanAlgorithm
Links
https://en.wikipedia.org/wiki/International_Standard_Audiovisual_Number https://www.isan.org/docs/isan_check_digit_calculation_v2.0.pdf https://web.isan.org/public/en/search
ISIN Algorithm
Description
The ISIN (International Securities Identification Number) algorithm uses a variation of the Luhn algorithm and has all of the capabilities of the Luhn algorithm, including the ability to detect all single digit (or character) transcription errors and most two digit transposition errors except 09 → 90 and vice versa.
The algorithm has significant weaknesses. Transpositions of two letters cannot be detected. Additionally, transpositions of a digit character and the letters B, M or X cannot be detected (because B is converted to 11, M to 22 and X to 33 and when combined with another digit, the result is a jump transposition that the Luhn algorithm cannot detect).
Details
- Valid characters - alphanumeric characters ('0' - '9', 'A' - 'Z')
- Check digit size - one character
- Check digit value - decimal digit ('0' - '9')
- Check digit location - assumed to be the trailing (right-most) character when validating
- Value length - 12
- Class name -
IsinAlgorithm
Links
Wikipedia: https://en.wikipedia.org/wiki/International_Securities_Identification_Number
ISO 6346 Algorithm
The ISO 6346 algorithm is used for eleven character shipping container numbers.
Details
- Valid characters - alphanumeric characters ('0' - '9', 'A' - 'Z')
- Check digit size - one character
- Check digit value - decimal digit ('0' - '9')
- Check digit location - assumed to be the trailing (right-most) character when validating
- Value length - 11
- Class name -
Iso6346Algorithm
Links
Wikipedia: https://en.wikipedia.org/wiki/ISO_6346
ISO/IEC 7064 MOD 11,10 Algorithm
The ISO/IEC 7064 MOD 11,10 algorithm is a hybrid system algorithm (with M = 10 and M+1 = 11) that is suitable for use with numeric strings. It generates a single check character that is a decimal digit.
Details
- Valid characters - decimal digits ('0' - '9')
- Check digit size - one character
- Check digit value - decimal digit ('0' - '9')
- Check digit location - assumed to be the trailing (right-most) character when validating
- Class name -
Iso7064Mod11_10Algorithm
ISO/IEC 7064 MOD 11-2 Algorithm
The ISO/IEC 7064 MOD 11-2 algorithm is a pure system algorithm (with modulus 11 and radix 2) that is suitable for use with numeric strings. It generates a single check character that is either a decimal digit or a supplementary 'X' character.
Details
- Valid characters - decimal digits ('0' - '9')
- Check digit size - one character
- Check digit value - either decimal digit ('0' - '9') or an uppercase 'X'
- Check digit location - assumed to be the trailing (right-most) character when validating
- Class name -
Iso7064Mod11_2Algorithm
Common Applications
- International Standard Name Identifier (ISNI)
ISO/IEC 7064 MOD 1271-36 Algorithm
The ISO/IEC 7064 MOD 1271-36 algorithm is a pure system algorithm (with modulus 1271 and radix 36) that is suitable for use with alphanumeric strings. It generates two check alphanumeric characters.
Details
- Valid characters - alphanumeric characters ('0' - '9', 'A' - 'Z')
- Check digit size - two characters
- Check digit value - alphanumeric characters ('0' - '9', 'A' - 'Z')
- Check digit location - assumed to be the trailing (right-most) characters when validating
- Class name -
Iso7064Mod1271_36Algorithm
ISO/IEC 7064 MOD 27,26 Algorithm
The ISO/IEC 7064 MOD 27,26 algorithm is a hybrid system algorithm (with M = 26 and M+1 = 27) that is suitable for use with alphabetic strings. It generates a single check character that is an alphabetic character.
Details
- Valid characters - alphabetic characters ('A' - 'Z')
- Check digit size - one character
- Check digit value - alphabetic characters ('A' - 'Z')
- Check digit location - assumed to be the trailing (right-most) character when validating
- Class name - Iso7064Mod27_26Algorithm
ISO/IEC 7064 MOD 37-2 Algorithm
The ISO/IEC 7064 MOD 37-2 algorithm is a pure system algorithm (with modulus 37 and radix 2) that is suitable for use with alphanumeric strings. It generates a single check character that is either an alphanumeric character or a supplementary '*' character.
Details
- Valid characters - alphanumeric characters ('0' - '9', 'A' - 'Z')
- Check digit size - one character
- Check digit value - either decimal digit ('0' - '9', 'A' - 'Z') or an asterisk '*'
- Check digit location - assumed to be the trailing (right-most) character when validating
- Class name -
Iso7064Mod37_2Algorithm
Common Applications
- International Society of Blood Transfusion (ISBT) Donation Identification Numbers
ISO/IEC 7064 MOD 37,36 Algorithm
The ISO/IEC 7064 MOD 37,36 algorithm is a hybrid system algorithm (with M = 36 and M+1 = 37) that is suitable for use with alphanumeric strings. It generates a single check character that is an alphanumeric character.
Details
- Valid characters - alphanumeric characters ('0' - '9', 'A' - 'Z')
- Check digit size - one character
- Check digit value - alphanumeric characters ('0' - '9', 'A' - 'Z')
- Check digit location - assumed to be the trailing (right-most) character when validating
- Class name -
Iso7064Mod37_36Algorithm
Common Applications
- Global Release Identifier (GRid)
ISO/IEC 7064 MOD 661-26 Algorithm
The ISO/IEC 7064 MOD 661-26 algorithm is a pure system algorithm (with modulus 661 and radix 26) that is suitable for use with alphabetic strings. It generates two check alphabetic characters.
Details
- Valid characters - alphabetic characters ('A' - 'Z')
- Check digit size - two characters
- Check digit value - alphabetic characters ('A' - 'Z')
- Check digit location - assumed to be the trailing (right-most) characters when validating
- Class name -
Iso7064Mod661_26Algorithm
ISO/IEC 7064 MOD 97-10 Algorithm
The ISO/IEC 7064 MOD 97-10 algorithm is a pure system algorithm (with modulus 97 and radix 210) that is suitable for use with numeric strings. It generates two numeric check digits.
Note: the ISO/IEC 7064 MOD 97-10 algorithm is the basis of a number of check digit algorithms that first map alphabetic characters to numbers between 10 and 35. Examples include International Bank Account Numbers (IBAN) and Universal Loan Identifiers (ULI). However this implementation is limited to values containing only decimal digits. Other algorithms will handle values like IBAN and ULI and perform the mapping of alphabetic characters internally.
Details
- Valid characters - decimal digits ('0' - '9')
- Check digit size - two characters
- Check digit value - decimal digits ('0' - '9')
- Check digit location - assumed to be the trailing (right-most) characters when validating
- Class name -
Iso7064Mod97_10Algorithm
Luhn Algorithm
Description
The Luhn algorithm is a modulus 10 algorithm that was developed in 1960 by Hans Peter Luhn. It can detect all single digit transcription errors and most two digit transposition errors except 09 → 90 and vice versa. It can also detect most twin errors (i.e. 11 ↔ 44) except 22 ↔ 55, 33 ↔ 66 and 44 ↔ 77.
LuhnAlgorithm implements IMaskedCheckDigitAlgorithm and can be used
to validate values that are formatted with non-check digit characters (for example,
a credit card number formatted with spaces or dashes).
Details
- Valid characters - decimal digits ('0' - '9')
- Check digit size - one character
- Check digit value - decimal digit ('0' - '9')
- Check digit location - assumed to be the trailing (right-most) character when validating
- Class name -
LuhnAlgorithm
Common Applications
- Credit card numbers
- International Mobile Equipment Identity (IMEI) numbers
- Canadian Social Insurance Number (SIN)
Links
Wikipedia: https://en.wikipedia.org/wiki/Luhn_algorithm
Modulus10_1 Algorithm
The Modulus10 algorithm uses modulus 10 and each digit is weighted by its position in the value, starting with weight 1 for the right-most non-check digit character.
Modulus10_1Algorithm implements IMaskedCheckDigitAlgorithm and can be used
to validate values that are formatted with non-check digit characters (for example,
a value formatted with spaces or dashes for human readability).
Details
- Valid characters - decimal digits ('0' - '9')
- Check digit size - one character
- Check digit value - either decimal digit ('0' - '9')
- Check digit location - assumed to be the trailing (right-most) character when validating
- Max length - 9 characters when generating a check digit; 10 characters when validating
- Class name -
Modulus10_1Algorithm
Common Applications
- Chemical Abstracts Service (CAS) Registry Number
Links
Wikipedia: https://en.wikipedia.org/wiki/CAS_Registry_Number
Modulus10_2 Algorithm
The Modulus10 algorithm uses modulus 10 and each digit is weighted by its position in the value, starting with weight 2 for the right-most non-check digit character.
Modulus10_2Algorithm implements IMaskedCheckDigitAlgorithm and can be used
to validate values that are formatted with non-check digit characters (for example,
a value formatted with spaces or dashes for human readability).
Details
- Valid characters - decimal digits ('0' - '9')
- Check digit size - one character
- Check digit value - either decimal digit ('0' - '9')
- Check digit location - assumed to be the trailing (right-most) character when validating
- Max length - 9 characters when generating a check digit; 10 characters when validating
- Class name -
Modulus10_2Algorithm
Common Applications
- International Maritime Organization (IMO) Number
Links
Wikipedia: https://en.wikipedia.org/wiki/IMO_number
Modulus10_13 Algorithm
Description
The Modulus10_13 algorithm is a widely used modulus 10 algorithm that uses weights 1 and 3 (odd positions have weight 3, even positions have weight 1). It can detect all single digit transcription errors and ~89% of two digit transposition errors (except where the transposed digits have a difference of 5, i.e. 1 ↔ 6, 2 ↔ 7, etc.). The algorithm cannot detect two digit jump transpositions.
Modulus10_13Algorithm implements IMaskedCheckDigitAlgorithm and can be used
to validate values that are formatted with non-check digit characters (for example,
a value formatted with spaces or dashes for human readability).
Details
- Valid characters - decimal digits ('0' - '9')
- Check digit size - one character
- Check digit value - decimal digit ('0' - '9')
- Check digit location - assumed to be the trailing (right-most) character when validating
- Class name -
Modulus10_13Algorithm
Common Applications
- Global Trade Item Number (GTIN-8, GTIN-12, GTIN-13, GTIN-14)
- International Article Number/European Article Number (EAN-8, EAN-13)
- International Standard Book Number, starting January 1, 2007 (ISBN-13)
- International Standard Music Number (ISMN)
- Serial Shipping Container Code (SSCC)
- Universal Product Code (UPC-A, UPC-E)
Links
Wikipedia: https://en.wikipedia.org/wiki/Universal_Product_Code#Check_digit_calculation https://en.wikipedia.org/wiki/International_Article_Number#Calculation_of_checksum_digit
Modulus11 Algorithm
Description
NOTE: This algorithm has been deprecated in favor of using the Modulus11Extended algorithm.
The Modulus11 algorithm uses modulus 11 and each digit is weighted by its position in the value, starting from the right-most digit. Prior to the existence of the Verhoeff algorithm and the Damm algorithm it was popular because it was able to detect two digit transposition errors while using only a single character. However, because it used modulus 11, the check digit could not be a single decimal digit. Commonly an 'X' character was used when the modulus operation resulted in a value of 10. This meant that identifiers that used the Modulus11 algorithm could not be stored as numbers and instead must be strings.
Details
- Valid characters - decimal digits ('0' - '9')
- Check digit size - one character
- Check digit value - either decimal digit ('0' - '9') or an uppercase 'X'
- Check digit location - assumed to be the trailing (right-most) character when validating
- Max length - 9 characters when generating a check digit; 10 characters when validating
- Class name -
Modulus11Algorithm
Common Applications
- International Standard Book Number, prior to January 1, 2007 (ISBN-10)
- International Standard Serial Number (ISSN)
Links
Wikipedia: https://en.wikipedia.org/wiki/ISBN#ISBN-10_check_digits https://en.wikipedia.org/wiki/ISSN
Modulus11_27Decimal Algorithm
The Modulus11_27Decimal algorithm uses modulus 11 and the IBM modulus 11 weighting scheme where each digit is weighted by the repeating sequence of weights 2, 3, 4, 5, 6, 7 starting with weight 2 for the right-most non-check digit character. The sequence of weights is repeated as necessary for values longer than 6 characters.
Prior to the existence of the Verhoeff algorithm and the Damm algorithm, modulus 11 algorithms were popular because they were very capable of detecting two digit transposition errors while using only a single check character. However, because it used modulus 11, the check character could not be a single decimal digit.
There are two common solutions to this problem: use a non-digit character to represent the 11th possible check value or reject any value that would require a non-digit check character. Using a non-digit check character (commonly 'X') means that the value is not an integer and must be stored as a string. Rejecting any value that could require a non-digit check character means that one out of eleven possible values must be rejected, or approximately 9.09% of all values.
The Modulus11_27Decimal algorithm takes the latter approach and the TryCalculateCheckDigit
and Validate methods return false if the value would require a non-digit check
character.
Modulus11_27DecimalAlgorithm implements IMaskedCheckDigitAlgorithm and can be used
to validate values that are formatted with non-check digit characters (for example,
a value formatted with spaces or dashes for human readability).
Details
- Valid characters - decimal digits ('0' - '9')
- Check digit size - one character
- Check digit value - either decimal digit ('0' - '9')
- Check digit location - assumed to be the trailing (right-most) character when validating
- Class name -
Modulus11_27DecimalAlgorithm
Common Applications
- Norwegian f�dselsnummer (Norwegian National Identity Number), second of two included check digits
Links
Wikipedia: https://en.wikipedia.org/wiki/National_identity_number_(Norway)
https://www.ibm.com/docs/en/rbd/9.6.0?topic=syslib-calculatechkdigitmod11
Modulus11_27Extended Algorithm
The Modulus11_27Extended algorithm uses modulus 11 and the IBM modulus 11 weighting scheme where each digit is weighted by the repeating sequence of weights 2, 3, 4, 5, 6, 7 starting with weight 2 for the right-most non-check digit character. The sequence of weights is repeated as necessary for values longer than 6 characters.
Prior to the existence of the Verhoeff algorithm and the Damm algorithm, modulus 11 algorithms were popular because they were very capable of detecting two digit transposition errors while using only a single check character. However, because it used modulus 11, the check character could not be a single decimal digit.
There are two common solutions to this problem: use a non-digit character to represent the 11th possible check value or reject any value that would require a non-digit check character. Using a non-digit check character (commonly 'X') means that the value is not an integer and must be stored as a string. Rejecting any value that could require a non-digit check character means that one out of eleven possible values must be rejected, or approximately 9.09% of all values.
The Modulus11_27Extended algorithm takes the former approach and the TryCalculateCheckDigit
and Validate allow values that include 'X' as an extended check character.
Modulus11_27ExtendedAlgorithm implements IMaskedCheckDigitAlgorithm and can be used
to validate values that are formatted with non-check digit characters (for example,
a value formatted with spaces or dashes for human readability).
Details
- Valid characters - decimal digits ('0' - '9')
- Check digit size - one character
- Check digit value - either decimal digit ('0' - '9') or an uppercase 'X'
- Check digit location - assumed to be the trailing (right-most) character when validating
- Class name -
Modulus11_27ExtendedAlgorithm
Modulus11Decimal Algorithm
Description
The Modulus11Decimal algorithm uses modulus 11 and each digit is weighted by its position in the value, starting from the right-most digit. Prior to the existence of the Verhoeff algorithm and the Damm algorithm, modulus 11 algorithms were popular because they were very capable of detecting two digit transposition errors while using only a single check character. However, because it used modulus 11, the check character could not be a single decimal digit.
There are two common solutions to this problem: use a non-digit character to represent the 11th possible check value or reject any value that would require a non-digit check character. Using a non-digit check character (commonly 'X') means that the value is not an integer and must be stored as a string. Rejecting any value that could require a non-digit check character means that one out of eleven possible values must be rejected, or approximately 9.09% of all values.
The Modulus11Decimal algorithm takes the latter approach and the TryCalculateCheckDigit
and Validate methods return false if the value would require a non-digit check
character.
Modulus11Decimal is a generalized version of the NhsAlgorithm which drops the fixed 10 character length required by NhsAlgorithm.
Modulus11DecimalAlgorithm implements IMaskedCheckDigitAlgorithm and can be used
to validate values that are formatted with non-check digit characters (for example,
a value formatted with spaces or dashes for human readability).
Details
- Valid characters - decimal digits ('0' - '9')
- Check digit size - one character
- Check digit value - either decimal digit ('0' - '9')
- Check digit location - assumed to be the trailing (right-most) character when validating
- Max length - 9 characters when generating a check digit; 10 characters when validating
- Class name -
Modulus11DecimalAlgorithm
Common Applications
- UK National Health Service Number
Links
Wikipedia: https://en.wikipedia.org/wiki/NHS_number#Format,_number_ranges,_and_check_characters
Modulus11Extended Algorithm
Description
The Modulus11Extended algorithm uses modulus 11 and each digit is weighted by its position in the value, starting from the right-most digit. Prior to the existence of the Verhoeff algorithm and the Damm algorithm, modulus 11 algorithms were popular because they were very capable of detecting two digit transposition errors while using only a single check character. However, because it used modulus 11, the check character could not be a single decimal digit.
There are two common solutions to this problem: use a non-digit character to represent the 11th possible check value or reject any value that would require a non-digit check character. Using a non-digit check character (commonly 'X') means that the value is not an integer and must be stored as a string. Rejecting any value that could require a non-digit check character means that one out of eleven possible values must be rejected, or approximately 9.09% of all values.
The Modulus11Extended algorithm takes the former approach and the TryCalculateCheckDigit
and Validate allow values that include 'X' as an extended check character.
Modulus11ExtendedAlgorithm implements IMaskedCheckDigitAlgorithm and can be used
to validate values that are formatted with non-check digit characters (for example,
a value formatted with spaces or dashes for human readability).
Modulus11Extended replaces the deprecated Modulus11 algorithm.
Details
- Valid characters - decimal digits ('0' - '9')
- Check digit size - one character
- Check digit value - either decimal digit ('0' - '9') or an uppercase 'X'
- Check digit location - assumed to be the trailing (right-most) character when validating
- Max length - 9 characters when generating a check digit; 10 characters when validating
- Class name -
Modulus11ExtendedAlgorithm
Common Applications
- International Standard Book Number, prior to January 1, 2007 (ISBN-10)
- International Standard Serial Number (ISSN)
Links
Wikipedia: https://en.wikipedia.org/wiki/ISBN#ISBN-10_check_digits https://en.wikipedia.org/wiki/ISSN
NHS Algorithm
Description
NOTE: This algorithm has been deprecated in favor of using the Modulus11Decimal algorithm.
UK National Health Service (NHS) identifiers use a variation of the Modulus 11 algorithm. However, instead of generating 11 possible values for the check digit, the NHS algorithm does not allow a remainder of 10 (the 'X' character used by the Modulus 11 algorithm). Any possible NHS number that would generate a remainder of 10 is not allowed and those numbers are not issued. This means that the check digit for a NHS number remains '0' - '9'. The NHS algorithm retains all error detecting capabilities of the Modulus 11 algorithm (detecting all single digit transcription errors and all two digit transposition errors).
The NHS algorithm only supports validation of check digits and does not support calculation of check digits.
Details
- Valid characters - decimal digits ('0' - '9')
- Check digit size - one character
- Check digit value - decimal digit ('0' - '9')
- Check digit location - assumed to be the trailing (right-most) character when validating
- Value length - 10 characters
- Class name -
NhsAlgorithm
Links
Wikipedia: https://en.wikipedia.org/wiki/NHS_number#Format,_number_ranges,_and_check_characters https://www.datadictionary.nhs.uk/attributes/nhs_number.html
NOID Check Digit Algorithm
Description
The NOID (Nice Opaque Identifier) Check Digit Algorithm is used by systems that deal with persistent identifiers (for example, ARK (Archival Resource Key) identifiers). The algorithm can detect single character transcription errors and two character transposition errors for values that are less than 29 characters in length. If the value is 29 character in length or greater then the algorithm is slightly less capable. The algorithm operates on lower case betanumeric characters (i.e. alphanumeric characters, minus vowels, including 'y', and the letter 'l'). The use of betanumeric characters reduces the likelihood that an identifier would equal a recognizable word or that the digits 0 or 1 could be confused for the letters 'o' or 'l'.
Details
- Valid characters - betanumeric characters ('0123456789bcdfghjkmnpqrstvwxz')
- Check digit size - one character
- Check digit value - betanumeric characters ('0123456789bcdfghjkmnpqrstvwxz')
- Check digit location - assumed to be the trailing (right-most) character when validating
- Class name -
NcdAlgorithm
Links
https://metacpan.org/dist/Noid/view/noid#NOID-CHECK-DIGIT-ALGORITHM
NPI Algorithm
Description
US National Provider Identifiers (NPI) use the Luhn algorithm to calculate the check digit located in the trailing (right-most) position. However, before calculating, the value is prefixed with a constant "80840" and the check digit is calculated using the entire 15 digit string. The resulting check digit has all the capabilities of the base Luhn algorithm (detecting all single digit transcription errors and most two digit transposition errors except 09 → 90 and vice versa as well as most twin errors (i.e. 11 ↔ 44) except 22 ↔ 55, 33 ↔ 66 and 44 ↔ 77.
(You can create and validate NPI check digits using the standard Luhn algorithm by first prefixing your value with "80840". However, CheckDigits.Net's implementation of the NPI algorithm handles the prefix internally and without allocating an extra string.)
The NPI algorithm only supports validation of check digits and does not support calculation of check digits.
Details
- Valid characters - decimal digits ('0' - '9')
- Check digit size - one character
- Check digit value - decimal digit ('0' - '9')
- Check digit location - assumed to be the trailing (right-most) character when validating
- Value length - 10 characters
- Class name -
NpiAlgorithm
Links
Wikipedia: https://en.wikipedia.org/wiki/National_Provider_Identifier
SEDOL Algorithm
Description
The SEDOL (Stock Exchange Daily Official List) algorithm is used for seven character alphanumeric codes that identify financial securities in the United Kingdom and Ireland.
The SEDOL algorithm only supports validation of check digits and does not support calculation of check digits.
Details
- Valid characters - alphanumeric characters, excluding vowels ('0' - '9', 'BCDFGHJKLMNPQRSTVWXYZ')
- Check digit size - one character
- Check digit value - decimal digit ('0' - '9')
- Check digit location - assumed to be the trailing (right-most) character when validating
- Value length - 7 characters
- Class name -
SedolAlgorithm
Links
Wikipedia: https://en.wikipedia.org/wiki/SEDOL
Verhoeff Algorithm
Description
The Verhoeff algorithm was the first algorithm using a single decimal check digit that was capable of detecting all single digit transcription errors and all two digit transposition errors. It was first described by Jacobus Verhoeff in 1969. Prior to Verhoeff it was believed that it was not possible to define an algorithm that used a single decimal check digit that could detect both all single digit transcription errors and all two digit transposition errors. Verhoeff's algorithm does not use modulus operations and instead uses a dihedral group (typically implemented as a set of lookup tables). Additionally, Verhoeff's algorithm can detect many, though not all, twin errors, two digit jump transpositions and jump twin errors.
VerhoeffAlgorithm implements IMaskedCheckDigitAlgorithm and can be used
to validate values that are formatted with non-check digit characters (for example,
a credit card number formatted with spaces or dashes).
Details
- Valid characters - decimal digits ('0' - '9')
- Check digit size - one character
- Check digit value - decimal digit ('0' - '9')
- Check digit location - assumed to be the trailing (right-most) character when validating
- Class name -
VerhoeffAlgorithm
Links
Wikipedia: https://en.wikipedia.org/wiki/Verhoeff_algorithm
VIN Algorithm
Description
The VIN (Vehicle Identification Number) algorithm is used on the VIN of vehicles sold in North America (US and Canada). The check digit is the 9th character of the 17 character value. Upper-case alphabetic characters (except 'I', 'O' and 'Q') are allowed in the value and must be transliterated to integer values before weighting, summing and calculating sum modulus 11.
Details
- Valid characters - decimal digits ('0' - '9') and upper case letters ('A' - 'Z'), excluding 'I', 'O' and 'Q'
- Check digit size - one character
- Check digit value - either decimal digit ('0' - '9') or an uppercase 'X'
- Check digit location - 9th character of 17
- Length - 17 characters
- Class name -
VinAlgorithm
Links
Wikipedia: https://en.wikipedia.org/wiki/Vehicle_identification_number#Check-digit_calculation
Benchmarks
The methodology for the general algorithms is to generate values for the benchmarks by taking substrings of lengths 3, 6, 9, etc. from the same randomly generated source string. For the TryCalculateCheckDigit or TryCalculateCheckDigits methods the substring is used as is. For the Validate method benchmarks the substring is appended with the check character or characters that make the test value valid for the algorithm being benchmarked.
For value specific algorithms, three separate values that are valid for the algorithm being benchmarked are used.
Previous .Net 8 benchmarks available at https://github.com/KnowledgeForwardSolutions/CheckDigits.Net/blob/main/Documentation/DotNet8Benchmarks.md
Detailed benchmark results for .Net 8 vs .Net 10 located at https://github.com/KnowledgeForwardSolutions/CheckDigits.Net/blob/main/Documentation/DotNet8_DotNet10_PerformanceComparision.md
Note that the benchmarks for version 2.x.x of CheckDigits.Net were run on an Intel i7-7700HQ CPU @ 2.80GHz computer while the benchmarks for version 3.x.x of CheckDigits.Net were run on an AMD RYZEN AI MAX+ 3950 CPU @ 3.00GHz computer. The comparison benchmarks between .Net 8.0 and .Net 10.0 were all run on the same newer computer to ensure accurate comparisons.
Benchmark Details
BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.7462/25H2/2025Update/HudsonValley2) AMD RYZEN AI MAX+ 395 w/ Radeon 8060S 3.00GHz, 1 CPU, 32 logical and 16 physical cores .NET SDK 10.0.101 [Host] : .NET 10.0.1 (10.0.1, 10.0.125.57005), X64 RyuJIT x86-64-v4 DefaultJob : .NET 10.0.1 (10.0.1, 10.0.125.57005), X64 RyuJIT x86-64-v4
TryCalculateCheckDigit/TryCalculateCheckDigits Methods
General Numeric Algorithms
Note that the Modulus10_1, Modulus10_2 and Modulus11 algorithms have a maximum length of 10 (including the check digit) for values being validated so their benchmarks do not cover lengths greater than 10.
| Algorithm Name | Value | Mean | Error | StdDev | Allocated |
|---|---|---|---|---|---|
| Damm | 140 | 1.956 ns | 0.0017 ns | 0.0015 ns | - |
| Damm | 140662 | 3.367 ns | 0.0102 ns | 0.0096 ns | - |
| Damm | 140662538 | 5.075 ns | 0.0045 ns | 0.0040 ns | - |
| Damm | 140662538042 | 7.286 ns | 0.0254 ns | 0.0238 ns | - |
| Damm | 140662538042551 | 9.441 ns | 0.0226 ns | 0.0212 ns | - |
| Damm | 140662538042551028 | 13.189 ns | 0.0125 ns | 0.0105 ns | - |
| Damm | 140662538042551028265 | 16.549 ns | 0.0689 ns | 0.0611 ns | - |
| ISO/IEC�706 MOD�11,10 | 140 | 2.256 ns | 0.0292 ns | 0.0273 ns | - |
| ISO/IEC�706 MOD�11,10 | 140662 | 4.046 ns | 0.0359 ns | 0.0318 ns | - |
| ISO/IEC�706 MOD�11,10 | 140662538 | 5.119 ns | 0.0255 ns | 0.0239 ns | - |
| ISO/IEC�706 MOD�11,10 | 140662538042 | 6.555 ns | 0.0703 ns | 0.0657 ns | - |
| ISO/IEC�706 MOD�11,10 | 140662538042551 | 8.083 ns | 0.0997 ns | 0.0933 ns | - |
| ISO/IEC�706 MOD�11,10 | 140662538042551028 | 9.338 ns | 0.0474 ns | 0.0420 ns | - |
| ISO/IEC�706 MOD�11,10 | 140662538042551028265 | 10.988 ns | 0.0404 ns | 0.0378 ns | - |
| ISO/IEC�706�MOD 11-2 | 140 | 2.235 ns | 0.0176 ns | 0.0165 ns | - |
| ISO/IEC�706�MOD 11-2 | 140662 | 3.839 ns | 0.0250 ns | 0.0234 ns | - |
| ISO/IEC�706�MOD 11-2 | 140662538 | 4.636 ns | 0.0240 ns | 0.0200 ns | - |
| ISO/IEC�706�MOD 11-2 | 140662538042 | 5.603 ns | 0.0362 ns | 0.0321 ns | - |
| ISO/IEC�706�MOD 11-2 | 140662538042551 | 6.611 ns | 0.0755 ns | 0.0707 ns | - |
| ISO/IEC�706�MOD 11-2 | 140662538042551028 | 7.308 ns | 0.0351 ns | 0.0329 ns | - |
| ISO/IEC�706�MOD 11-2 | 140662538042551028265 | 8.910 ns | 0.0669 ns | 0.0626 ns | - |
| ISO/IEC�706 MOD�97-10 | 140 | 2.926 ns | 0.0236 ns | 0.0221 ns | - |
| ISO/IEC�706 MOD�97-10 | 140662 | 4.230 ns | 0.0289 ns | 0.0270 ns | - |
| ISO/IEC�706 MOD�97-10 | 140662538 | 6.013 ns | 0.0216 ns | 0.0202 ns | - |
| ISO/IEC�706 MOD�97-10 | 140662538042 | 7.501 ns | 0.0379 ns | 0.0336 ns | - |
| ISO/IEC�706 MOD�97-10 | 140662538042551 | 9.122 ns | 0.0407 ns | 0.0361 ns | - |
| ISO/IEC�706 MOD�97-10 | 140662538042551028 | 11.271 ns | 0.0390 ns | 0.0364 ns | - |
| ISO/IEC�706 MOD�97-10 | 140662538042551028265 | 13.185 ns | 0.0484 ns | 0.0429 ns | - |
| Luhn | 140 | 2.739 ns | 0.0284 ns | 0.0265 ns | - |
| Luhn | 140662 | 4.375 ns | 0.0256 ns | 0.0227 ns | - |
| Luhn | 140662538 | 5.987 ns | 0.0550 ns | 0.0514 ns | - |
| Luhn | 140662538042 | 6.769 ns | 0.0602 ns | 0.0533 ns | - |
| Luhn | 140662538042551 | 8.452 ns | 0.0505 ns | 0.0448 ns | - |
| Luhn | 140662538042551028 | 9.905 ns | 0.0575 ns | 0.0538 ns | - |
| Luhn | 140662538042551028265 | 11.526 ns | 0.0598 ns | 0.0559 ns | - |
| Modulus10_13 | 140 | 2.536 ns | 0.0202 ns | 0.0179 ns | - |
| Modulus10_13 | 140662 | 4.280 ns | 0.0267 ns | 0.0250 ns | - |
| Modulus10_13 | 140662538 | 5.105 ns | 0.0284 ns | 0.0265 ns | - |
| Modulus10_13 | 140662538042 | 6.363 ns | 0.0230 ns | 0.0192 ns | - |
| Modulus10_13 | 140662538042551 | 7.715 ns | 0.0326 ns | 0.0305 ns | - |
| Modulus10_13 | 140662538042551028 | 9.209 ns | 0.0357 ns | 0.0334 ns | - |
| Modulus10_13 | 140662538042551028265 | 10.628 ns | 0.0633 ns | 0.0561 ns | - |
| Modulus10_1 | 140 | 1.808 ns | 0.0124 ns | 0.0096 ns | - |
| Modulus10_1 | 140662 | 2.587 ns | 0.0193 ns | 0.0171 ns | - |
| Modulus10_1 | 140662538 | 4.043 ns | 0.0233 ns | 0.0218 ns | - |
| Modulus10_2 | 140 | 1.854 ns | 0.0206 ns | 0.0183 ns | - |
| Modulus10_2 | 140662 | 2.656 ns | 0.0145 ns | 0.0136 ns | - |
| Modulus10_2 | 140662538 | 4.024 ns | 0.0173 ns | 0.0162 ns | - |
| Modulus11 | 140 | 2.364 ns | 0.0171 ns | 0.0152 ns | - |
| Modulus11 | 140662 | 3.323 ns | 0.0300 ns | 0.0280 ns | - |
| Modulus11 | 140662538 | 4.341 ns | 0.0301 ns | 0.0281 ns | - |
| Modulus11_27Decimal | 140 | 3.292 ns | 0.0590 ns | 0.0523 ns | - |
| Modulus11_27Decimal | 140662 | 4.785 ns | 0.0273 ns | 0.0255 ns | - |
| Modulus11_27Decimal | 140662538 | 5.915 ns | 0.0624 ns | 0.0583 ns | - |
| Modulus11_27Decimal | 140662538042 | 7.329 ns | 0.0601 ns | 0.0502 ns | - |
| Modulus11_27Decimal | 140662538042551 | 8.629 ns | 0.0962 ns | 0.0900 ns | - |
| Modulus11_27Decimal | 140662538042551028 | 9.721 ns | 0.1167 ns | 0.1035 ns | - |
| Modulus11_27Decimal | 140662538042551028265 | 11.694 ns | 0.1306 ns | 0.1090 ns | - |
| Modulus11_27Extended | 140 | 3.353 ns | 0.0221 ns | 0.0207 ns | - |
| Modulus11_27Extended | 140662 | 4.813 ns | 0.0994 ns | 0.0976 ns | - |
| Modulus11_27Extended | 140662538 | 6.043 ns | 0.0908 ns | 0.0849 ns | - |
| Modulus11_27Extended | 140662538042 | 7.206 ns | 0.0460 ns | 0.0407 ns | - |
| Modulus11_27Extended | 140662538042551 | 8.581 ns | 0.0666 ns | 0.0623 ns | - |
| Modulus11_27Extended | 140662538042551028 | 9.427 ns | 0.0393 ns | 0.0329 ns | - |
| Modulus11_27Extended | 140662538042551028265 | 11.830 ns | 0.1384 ns | 0.1295 ns | - |
| Modulus11Decimal | 140 | 2.322 ns | 0.0348 ns | 0.0325 ns | - |
| Modulus11Decimal | 140662 | 3.220 ns | 0.0485 ns | 0.0453 ns | - |
| Modulus11Decimal | 140662538 | 4.239 ns | 0.0544 ns | 0.0509 ns | - |
| Verhoeff | 140 | 4.250 ns | 0.0312 ns | 0.0277 ns | - |
| Verhoeff | 140662 | 6.399 ns | 0.0542 ns | 0.0452 ns | - |
| Verhoeff | 140662538 | 9.977 ns | 0.0363 ns | 0.0340 ns | - |
| Verhoeff | 140662538042 | 13.351 ns | 0.0441 ns | 0.0413 ns | - |
| Verhoeff | 140662538042551 | 16.793 ns | 0.0614 ns | 0.0574 ns | - |
| Verhoeff | 140662538042551028 | 19.818 ns | 0.0811 ns | 0.0758 ns | - |
| Verhoeff | 140662538042551028265 | 22.861 ns | 0.0866 ns | 0.0768 ns | - |
General Alphabetic Algorithms
| Algorithm Name | Value | Mean | Error | StdDev | Allocated |
|---|---|---|---|---|---|
| ISO/IEC 7064 MOD 27,26 | EGR | 2.178 ns | 0.0032 ns | 0.0030 ns | - |
| ISO/IEC 7064 MOD 27,26 | EGRNML | 3.900 ns | 0.0091 ns | 0.0085 ns | - |
| ISO/IEC 7064 MOD 27,26 | EGRNMLJOC | 5.088 ns | 0.0505 ns | 0.0472 ns | - |
| ISO/IEC 7064 MOD 27,26 | EGRNMLJOCECU | 6.933 ns | 0.0953 ns | 0.0891 ns | - |
| ISO/IEC 7064 MOD 27,26 | EGRNMLJOCECUJIK | 7.753 ns | 0.0516 ns | 0.0458 ns | - |
| ISO/IEC 7064 MOD 27,26 | EGRNMLJOCECUJIKNWW | 9.899 ns | 0.2137 ns | 0.3570 ns | - |
| ISO/IEC 7064 MOD 27,26 | EGRNMLJOCECUJIKNWWVVO | 11.228 ns | 0.2467 ns | 0.4694 ns | - |
| ISO/IEC 7064 MOD 661-26 | EGR | 3.193 ns | 0.0212 ns | 0.0198 ns | - |
| ISO/IEC 7064 MOD 661-26 | EGRNML | 4.940 ns | 0.0303 ns | 0.0268 ns | - |
| ISO/IEC 7064 MOD 661-26 | EGRNMLJOC | 6.459 ns | 0.0187 ns | 0.0174 ns | - |
| ISO/IEC 7064 MOD 661-26 | EGRNMLJOCECU | 8.844 ns | 0.0380 ns | 0.0297 ns | - |
| ISO/IEC 7064 MOD 661-26 | EGRNMLJOCECUJIK | 11.127 ns | 0.0432 ns | 0.0361 ns | - |
| ISO/IEC 7064 MOD 661-26 | EGRNMLJOCECUJIKNWW | 13.005 ns | 0.0354 ns | 0.0331 ns | - |
| ISO/IEC 7064 MOD 661-26 | EGRNMLJOCECUJIKNWWVVO | 15.670 ns | 0.0925 ns | 0.0820 ns | - |
General Alphanumeric Algorithms
Note that the values used for the NOID Check Digit algorithm do not include lengths 3 or 6 so that benchmarks are not run on purely numeric strings.
| Algorithm Name | Value | Mean | Error | StdDev | Allocated |
|---|---|---|---|---|---|
| AlphanumericMod97_10 | U7y | 4.951 ns | 0.0035 ns | 0.0033 ns | - |
| AlphanumericMod97_10 | U7y8SX | 8.103 ns | 0.0134 ns | 0.0112 ns | - |
| AlphanumericMod97_10 | U7y8SXrC0 | 11.861 ns | 0.0131 ns | 0.0116 ns | - |
| AlphanumericMod97_10 | U7y8SXrC0O3S | 14.879 ns | 0.0324 ns | 0.0270 ns | - |
| AlphanumericMod97_10 | U7y8SXrC0O3Sc4I | 19.017 ns | 0.0234 ns | 0.0219 ns | - |
| AlphanumericMod97_10 | U7y8SXrC0O3Sc4IHYQ | 24.122 ns | 0.0783 ns | 0.0654 ns | - |
| AlphanumericMod97_10 | U7y8SXrC0O3Sc4IHYQF4M | 28.224 ns | 0.0837 ns | 0.0742 ns | - |
| ISO/IEC 7064 MOD 1271-36 | U7Y | 3.993 ns | 0.0239 ns | 0.0223 ns | - |
| ISO/IEC 7064 MOD 1271-36 | U7Y8SX | 5.886 ns | 0.0195 ns | 0.0173 ns | - |
| ISO/IEC 7064 MOD 1271-36 | U7Y8SXRC0 | 7.876 ns | 0.0498 ns | 0.0466 ns | - |
| ISO/IEC 7064 MOD 1271-36 | U7Y8SXRC0O3S | 9.690 ns | 0.0557 ns | 0.0494 ns | - |
| ISO/IEC 7064 MOD 1271-36 | U7Y8SXRC0O3SC4I | 12.064 ns | 0.0856 ns | 0.0801 ns | - |
| ISO/IEC 7064 MOD 1271-36 | U7Y8SXRC0O3SC4IHYQ | 14.832 ns | 0.0857 ns | 0.0760 ns | - |
| ISO/IEC 7064 MOD 1271-36 | U7Y8SXRC0O3SC4IHYQF4M | 17.734 ns | 0.1363 ns | 0.1275 ns | - |
| ISO/IEC 7064 MOD 37-2 | U7Y | 3.182 ns | 0.0303 ns | 0.0253 ns | - |
| ISO/IEC 7064 MOD 37-2 | U7Y8SX | 4.540 ns | 0.0299 ns | 0.0280 ns | - |
| ISO/IEC 7064 MOD 37-2 | U7Y8SXRC0 | 6.188 ns | 0.0817 ns | 0.0764 ns | - |
| ISO/IEC 7064 MOD 37-2 | U7Y8SXRC0O3S | 6.959 ns | 0.0358 ns | 0.0299 ns | - |
| ISO/IEC 7064 MOD 37-2 | U7Y8SXRC0O3SC4I | 8.238 ns | 0.0535 ns | 0.0474 ns | - |
| ISO/IEC 7064 MOD 37-2 | U7Y8SXRC0O3SC4IHYQ | 9.840 ns | 0.0572 ns | 0.0507 ns | - |
| ISO/IEC 7064 MOD 37-2 | U7Y8SXRC0O3SC4IHYQF4M | 10.781 ns | 0.0573 ns | 0.0508 ns | - |
| ISO/IEC 7064 MOD 37,36 | U7Y | 3.191 ns | 0.0277 ns | 0.0231 ns | - |
| ISO/IEC 7064 MOD 37,36 | U7Y8SX | 4.903 ns | 0.0462 ns | 0.0432 ns | - |
| ISO/IEC 7064 MOD 37,36 | U7Y8SXRC0 | 6.787 ns | 0.1198 ns | 0.1120 ns | - |
| ISO/IEC 7064 MOD 37,36 | U7Y8SXRC0O3S | 8.334 ns | 0.0563 ns | 0.0499 ns | - |
| ISO/IEC 7064 MOD 37,36 | U7Y8SXRC0O3SC4I | 9.866 ns | 0.0656 ns | 0.0548 ns | - |
| ISO/IEC 7064 MOD 37,36 | U7Y8SXRC0O3SC4IHYQ | 11.466 ns | 0.0786 ns | 0.0735 ns | - |
| ISO/IEC 7064 MOD 37,36 | U7Y8SXRC0O3SC4IHYQF4M | 13.145 ns | 0.0616 ns | 0.0577 ns | - |
| NOID Check Digit | 11404/2h9 | 4.511 ns | 0.0313 ns | 0.0262 ns | - |
| NOID Check Digit | 11404/2h9tqb | 6.029 ns | 0.0305 ns | 0.0285 ns | - |
| NOID Check Digit | 11404/2h9tqbxk6 | 7.134 ns | 0.0436 ns | 0.0407 ns | - |
| NOID Check Digit | 11404/2h9tqbxk6rw7 | 8.861 ns | 0.0767 ns | 0.0718 ns | - |
| NOID Check Digit | 11404/2h9tqbxk6rw7dwm | 10.324 ns | 0.0848 ns | 0.0793 ns | - |
Value Specific Algorithms
Note: ABA RTN, CUSIP, ICAO 9303 multi-field algorithms (Machine Readable Visa, Size TD1, TD2 and TD3), ISAN, NHS, NPI and SEDOL algorithms do not support calculation of check digits, only validation of values containing check digits.
| Algorithm Name | Value | Mean | Error | StdDev | Allocated |
|---|---|---|---|---|---|
| IBAN | BE00096123456769 | 12.797 ns | 0.0626 ns | 0.0586 ns | - |
| IBAN | GB00WEST12345698765432 | 22.264 ns | 0.2030 ns | 0.1695 ns | - |
| IBAN | SC00MCBL01031234567890123456USD | 33.121 ns | 0.1529 ns | 0.1355 ns | - |
| ICAO 9303 | U7Y | 4.275 ns | 0.0977 ns | 0.0960 ns | - |
| ICAO 9303 | U7Y8SX | 5.637 ns | 0.0558 ns | 0.0436 ns | - |
| ICAO 9303 | U7Y8SXRC0 | 7.426 ns | 0.0747 ns | 0.0699 ns | - |
| ICAO 9303 | U7Y8SXRC0O3S | 9.916 ns | 0.0626 ns | 0.0555 ns | - |
| ICAO 9303 | U7Y8SXRC0O3SC4I | 12.295 ns | 0.0660 ns | 0.0551 ns | - |
| ICAO 9303 | U7Y8SXRC0O3SC4IHYQ | 14.716 ns | 0.1333 ns | 0.1247 ns | - |
| ICAO 9303 | U7Y8SXRC0O3SC4IHYQF4M | 16.864 ns | 0.1193 ns | 0.1116 ns | - |
| ISIN | AU0000XVGZA | 7.917 ns | 0.0690 ns | 0.0645 ns | - |
| ISIN | GB000263494 | 7.118 ns | 0.0536 ns | 0.0475 ns | - |
| ISIN | US037833100 | 7.132 ns | 0.0948 ns | 0.0792 ns | - |
| ISO 6346 | CSQU305438 | 7.445 ns | 0.0693 ns | 0.0579 ns | - |
| ISO 6346 | MSKU907032 | 7.493 ns | 0.0903 ns | 0.0800 ns | - |
| ISO 6346 | TOLU473478 | 7.467 ns | 0.0621 ns | 0.0550 ns | - |
| VIN | 1G8ZG127_WZ157259 | 13.113 ns | 0.0649 ns | 0.0542 ns | - |
| VIN | 1HGEM212_2L047875 | 12.975 ns | 0.0850 ns | 0.0710 ns | - |
| VIN | 1M8GDM9A_KP042788 | 13.377 ns | 0.1008 ns | 0.0942 ns | - |
Damm Custom Quasigroup Algorithm
Note: The Order 10 quasigroup class used in the benchmarks is the one used as an example for IDammQuasigroup. The Order 16 quasigroup class used in the benchmarks is the one used as an example for DammCustomQuasigroup.
| Algorithm Name | Value | Mean | Error | StdDev | Allocated |
|---|---|---|---|---|---|
| Damm Custom Quasigroup (Order = 10) | 140 | 4.029 ns | 0.0847 ns | 0.0751 ns | - |
| Damm Custom Quasigroup (Order = 10) | 140662 | 5.350 ns | 0.0282 ns | 0.0250 ns | - |
| Damm Custom Quasigroup (Order = 10) | 140662538 | 7.117 ns | 0.0516 ns | 0.0457 ns | - |
| Damm Custom Quasigroup (Order = 10) | 140662538042 | 10.101 ns | 0.0883 ns | 0.0826 ns | - |
| Damm Custom Quasigroup (Order = 10) | 140662538042551 | 13.413 ns | 0.0617 ns | 0.0547 ns | - |
| Damm Custom Quasigroup (Order = 10) | 140662538042551028 | 16.592 ns | 0.2615 ns | 0.2446 ns | - |
| Damm Custom Quasigroup (Order = 10) | 140662538042551028265 | 19.340 ns | 0.0830 ns | 0.0736 ns | - |
| Damm Custom Quasigroup (Order = 16) | 2ED1 | 7.908 ns | 0.1747 ns | 0.3323 ns | - |
| Damm Custom Quasigroup (Order = 16) | 2EDC15F | 13.077 ns | 0.2627 ns | 0.2811 ns | - |
| Damm Custom Quasigroup (Order = 16) | 2EDC15B3C5 | 16.192 ns | 0.3371 ns | 0.3747 ns | - |
| Damm Custom Quasigroup (Order = 16) | 2EDC15B3C1C33 | 21.008 ns | 0.4251 ns | 0.6619 ns | - |
| Damm Custom Quasigroup (Order = 16) | 2EDC15B3C1C34F46 | 25.848 ns | 0.5336 ns | 0.9890 ns | - |
| Damm Custom Quasigroup (Order = 16) | 2EDC15B3C1C34F4DA52 | 29.608 ns | 0.6020 ns | 0.5631 ns | - |
| Damm Custom Quasigroup (Order = 16) | 2EDC15B3C1C34F4DA55F3 | 38.690 ns | 0.8004 ns | 1.6349 ns | - |
Validate Method
General Numeric Algorithms
All algorithms use a single check digit except ISO/IEC 7064 MOD 97-10 which uses two check digits.
Note that the Modulus10_1, Modulus10_2 and Modulus11 algorithms have a maximum length of 10 (including the check digit) for values being validated so their benchmarks do not cover lengths greater than 10.
| Algorithm Name | Value | Mean | Error | StdDev | Allocated |
|---|---|---|---|---|---|
| Damm | 1402 | 2.107 ns | 0.0153 ns | 0.0144 ns | - |
| Damm | 1406622 | 3.959 ns | 0.0172 ns | 0.0160 ns | - |
| Damm | 1406625388 | 6.171 ns | 0.0498 ns | 0.0441 ns | - |
| Damm | 1406625380422 | 8.236 ns | 0.0080 ns | 0.0071 ns | - |
| Damm | 1406625380425518 | 11.350 ns | 0.2009 ns | 0.1879 ns | - |
| Damm | 1406625380425510280 | 14.888 ns | 0.1275 ns | 0.1130 ns | - |
| Damm | 1406625380425510282654 | 17.861 ns | 0.1244 ns | 0.1103 ns | - |
| ISO/IEC�706 MOD�11,10 | 1409 | 2.482 ns | 0.0221 ns | 0.0196 ns | - |
| ISO/IEC�706 MOD�11,10 | 1406623 | 4.196 ns | 0.0318 ns | 0.0297 ns | - |
| ISO/IEC�706 MOD�11,10 | 1406625381 | 5.715 ns | 0.0421 ns | 0.0394 ns | - |
| ISO/IEC�706 MOD�11,10 | 1406625380426 | 6.553 ns | 0.0593 ns | 0.0526 ns | - |
| ISO/IEC�706 MOD�11,10 | 1406625380425514 | 8.079 ns | 0.1089 ns | 0.0909 ns | - |
| ISO/IEC�706 MOD�11,10 | 1406625380425510286 | 9.670 ns | 0.1054 ns | 0.0934 ns | - |
| ISO/IEC�706 MOD�11,10 | 1406625380425510282657 | 11.182 ns | 0.0617 ns | 0.0577 ns | - |
| ISO/IEC�706�MOD 11-2 | 140X | 2.074 ns | 0.0171 ns | 0.0152 ns | - |
| ISO/IEC�706�MOD 11-2 | 1406628 | 3.803 ns | 0.0240 ns | 0.0213 ns | - |
| ISO/IEC�706�MOD 11-2 | 1406625380 | 4.420 ns | 0.0263 ns | 0.0246 ns | - |
| ISO/IEC�706�MOD 11-2 | 1406625380426 | 5.091 ns | 0.0302 ns | 0.0282 ns | - |
| ISO/IEC�706�MOD 11-2 | 1406625380425511 | 5.880 ns | 0.0254 ns | 0.0225 ns | - |
| ISO/IEC�706�MOD 11-2 | 140662538042551028X | 6.881 ns | 0.0434 ns | 0.0385 ns | - |
| ISO/IEC�706�MOD 11-2 | 1406625380425510282651 | 7.915 ns | 0.0558 ns | 0.0466 ns | - |
| ISO/IEC�706 MOD�97-10 | 14066 | 2.411 ns | 0.0131 ns | 0.0122 ns | - |
| ISO/IEC�706 MOD�97-10 | 14066262 | 4.086 ns | 0.0298 ns | 0.0264 ns | - |
| ISO/IEC�706 MOD�97-10 | 14066253823 | 5.394 ns | 0.0314 ns | 0.0294 ns | - |
| ISO/IEC�706 MOD�97-10 | 14066253804250 | 6.914 ns | 0.0428 ns | 0.0380 ns | - |
| ISO/IEC�706 MOD�97-10 | 14066253804255112 | 8.808 ns | 0.0543 ns | 0.0508 ns | - |
| ISO/IEC�706 MOD�97-10 | 14066253804255102853 | 10.441 ns | 0.0491 ns | 0.0460 ns | - |
| ISO/IEC�706 MOD�97-10 | 14066253804255102826587 | 12.202 ns | 0.0511 ns | 0.0478 ns | - |
| Luhn | 1404 | 3.544 ns | 0.0239 ns | 0.0224 ns | - |
| Luhn | 1406628 | 4.607 ns | 0.0323 ns | 0.0286 ns | - |
| Luhn | 1406625382 | 6.550 ns | 0.0597 ns | 0.0558 ns | - |
| Luhn | 1406625380421 | 7.363 ns | 0.0547 ns | 0.0485 ns | - |
| Luhn | 1406625380425514 | 9.138 ns | 0.0823 ns | 0.0730 ns | - |
| Luhn | 1406625380425510285 | 10.409 ns | 0.0735 ns | 0.0614 ns | - |
| Luhn | 1406625380425510282651 | 12.164 ns | 0.0669 ns | 0.0626 ns | - |
| Modulus10_13 | 1403 | 3.020 ns | 0.0234 ns | 0.0219 ns | - |
| Modulus10_13 | 1406627 | 4.638 ns | 0.0212 ns | 0.0177 ns | - |
| Modulus10_13 | 1406625385 | 5.447 ns | 0.0333 ns | 0.0311 ns | - |
| Modulus10_13 | 1406625380425 | 6.674 ns | 0.0399 ns | 0.0333 ns | - |
| Modulus10_13 | 1406625380425518 | 8.093 ns | 0.0361 ns | 0.0320 ns | - |
| Modulus10_13 | 1406625380425510288 | 9.428 ns | 0.0437 ns | 0.0387 ns | - |
| Modulus10_13 | 1406625380425510282657 | 10.903 ns | 0.0325 ns | 0.0304 ns | - |
| Modulus10_1 | 1401 | 1.904 ns | 0.0188 ns | 0.0157 ns | - |
| Modulus10_1 | 1406628 | 2.879 ns | 0.0315 ns | 0.0295 ns | - |
| Modulus10_1 | 1406625384 | 4.125 ns | 0.0316 ns | 0.0295 ns | - |
| Modulus10_2 | 1406 | 1.847 ns | 0.0170 ns | 0.0151 ns | - |
| Modulus10_2 | 1406627 | 2.898 ns | 0.0227 ns | 0.0212 ns | - |
| Modulus10_2 | 1406625389 | 4.048 ns | 0.0270 ns | 0.0253 ns | - |
| Modulus11 | 1406 | 2.948 ns | 0.0241 ns | 0.0214 ns | - |
| Modulus11 | 1406620 | 4.062 ns | 0.0213 ns | 0.0200 ns | - |
| Modulus11 | 1406625388 | 4.506 ns | 0.0278 ns | 0.0247 ns | - |
| Modulus11_27Decimal | 1406 | 2.978 ns | 0.0309 ns | 0.0274 ns | - |
| Modulus11_27Decimal | 1406620 | 4.800 ns | 0.0882 ns | 0.0825 ns | - |
| Modulus11_27Decimal | 1406625385 | 5.773 ns | 0.0791 ns | 0.0740 ns | - |
| Modulus11_27Decimal | 1406625380421 | 6.889 ns | 0.0383 ns | 0.0340 ns | - |
| Modulus11_27Decimal | 1406625380425510 | 8.146 ns | 0.0545 ns | 0.0483 ns | - |
| Modulus11_27Decimal | 1406625380425510288 | 9.203 ns | 0.0955 ns | 0.0846 ns | - |
| Modulus11_27Decimal | 1406625380425510282650 | 10.384 ns | 0.0623 ns | 0.0521 ns | - |
| Modulus11_27Extended | 1406 | 3.252 ns | 0.0207 ns | 0.0193 ns | - |
| Modulus11_27Extended | 1406620 | 4.646 ns | 0.0365 ns | 0.0324 ns | - |
| Modulus11_27Extended | 1406625385 | 5.760 ns | 0.0251 ns | 0.0235 ns | - |
| Modulus11_27Extended | 1406625380421 | 7.035 ns | 0.0508 ns | 0.0476 ns | - |
| Modulus11_27Extended | 1406625380425510 | 8.416 ns | 0.0916 ns | 0.0812 ns | - |
| Modulus11_27Extended | 1406625380425510288 | 9.086 ns | 0.0228 ns | 0.0190 ns | - |
| Modulus11_27Extended | 1406625380425510282650 | 10.344 ns | 0.0773 ns | 0.0645 ns | - |
| Modulus11Decimal | 1406 | 1.892 ns | 0.0528 ns | 0.0791 ns | - |
| Modulus11Decimal | 1406620 | 3.126 ns | 0.0801 ns | 0.1403 ns | - |
| Modulus11Decimal | 1406625388 | 4.123 ns | 0.0335 ns | 0.0313 ns | - |
| Modulus11Extended | 1406 | 2.316 ns | 0.0099 ns | 0.0093 ns | - |
| Modulus11Extended | 1406620 | 3.931 ns | 0.0054 ns | 0.0051 ns | - |
| Modulus11Extended | 1406625388 | 4.563 ns | 0.0169 ns | 0.0158 ns | - |
| Verhoeff | 1401 | 4.827 ns | 0.0255 ns | 0.0239 ns | - |
| Verhoeff | 1406625 | 6.848 ns | 0.0410 ns | 0.0383 ns | - |
| Verhoeff | 1406625388 | 10.197 ns | 0.0473 ns | 0.0419 ns | - |
| Verhoeff | 1406625380426 | 13.644 ns | 0.0384 ns | 0.0340 ns | - |
| Verhoeff | 1406625380425512 | 17.068 ns | 0.0725 ns | 0.0643 ns | - |
| Verhoeff | 1406625380425510285 | 20.048 ns | 0.0891 ns | 0.0790 ns | - |
| Verhoeff | 1406625380425510282655 | 23.163 ns | 0.0715 ns | 0.0597 ns | - |
General Alphabetic Algorithms
ISO/IEC 7064 MOD 27,26 uses a single check character. ISO/IEC 7064 MOD 661-26 uses two check characters.
| Algorithm Name | Value | Mean | Error | StdDev | Allocated |
|---|---|---|---|---|---|
| ISO/IEC 7064 MOD 27,26 | EGRS | 2.332 ns | 0.0226 ns | 0.0211 ns | - |
| ISO/IEC 7064 MOD 27,26 | EGRNMLU | 4.097 ns | 0.0308 ns | 0.0273 ns | - |
| ISO/IEC 7064 MOD 27,26 | EGRNMLJOCB | 5.679 ns | 0.1293 ns | 0.2195 ns | - |
| ISO/IEC 7064 MOD 27,26 | EGRNMLJOCECUA | 7.347 ns | 0.1623 ns | 0.2379 ns | - |
| ISO/IEC 7064 MOD 27,26 | EGRNMLJOCECUJIKA | 9.034 ns | 0.1990 ns | 0.4729 ns | - |
| ISO/IEC 7064 MOD 27,26 | EGRNMLJOCECUJIKNWWY | 10.673 ns | 0.1450 ns | 0.1356 ns | - |
| ISO/IEC 7064 MOD 27,26 | EGRNMLJOCECUJIKNWWVVOQ | 11.102 ns | 0.1145 ns | 0.0956 ns | - |
| ISO/IEC 7064 MOD 661-26 | EGRSE | 2.641 ns | 0.0136 ns | 0.0121 ns | - |
| ISO/IEC 7064 MOD 661-26 | EGRNMLDR | 4.459 ns | 0.0364 ns | 0.0340 ns | - |
| ISO/IEC 7064 MOD 661-26 | EGRNMLJOCCK | 6.448 ns | 0.0262 ns | 0.0245 ns | - |
| ISO/IEC 7064 MOD 661-26 | EGRNMLJOCECUZJ | 8.374 ns | 0.0898 ns | 0.0796 ns | - |
| ISO/IEC 7064 MOD 661-26 | EGRNMLJOCECUJIKFQ | 10.262 ns | 0.0453 ns | 0.0402 ns | - |
| ISO/IEC 7064 MOD 661-26 | EGRNMLJOCECUJIKNWWQN | 13.125 ns | 0.0858 ns | 0.0760 ns | - |
| ISO/IEC 7064 MOD 661-26 | EGRNMLJOCECUJIKNWWVVORC | 15.238 ns | 0.0584 ns | 0.0546 ns | - |
General Alphanumeric Algorithms
AlphanumericMod97_10 algorithm and ISO/IEC 7064 MOD 1271-36 uses two check characters. ISO/IEC 7064 MOD 37-2, ISO/IEC 7064 MOD 37,36 and NOID Check Digit algorithms use a single check character.
Note also that the values used for the NOID Check Digit algorithm do not include lengths 3 or 6 so that benchmarks are not run on purely numeric strings.
| Algorithm Name | Value | Mean | Error | StdDev | Allocated |
|---|---|---|---|---|---|
| AlphanumericMod97_10 | U7y46 | 5.297 ns | 0.0975 ns | 0.0912 ns | - |
| AlphanumericMod97_10 | U7y8SX89 | 7.339 ns | 0.0166 ns | 0.0147 ns | - |
| AlphanumericMod97_10 | U7y8SXrC087 | 10.939 ns | 0.0123 ns | 0.0115 ns | - |
| AlphanumericMod97_10 | U7y8SXrC0O3S38 | 14.217 ns | 0.0401 ns | 0.0375 ns | - |
| AlphanumericMod97_10 | U7y8SXrC0O3Sc4I27 | 18.788 ns | 0.3287 ns | 0.7553 ns | - |
| AlphanumericMod97_10 | U7y8SXrC0O3Sc4IHYQ54 | 23.346 ns | 0.0715 ns | 0.0669 ns | - |
| AlphanumericMod97_10 | U7y8SXrC0O3Sc4IHYQF4M21 | 27.472 ns | 0.0671 ns | 0.0595 ns | - |
| ISO/IEC 7064 MOD 1271-36 | U7YM0 | 3.781 ns | 0.0263 ns | 0.0233 ns | - |
| ISO/IEC 7064 MOD 1271-36 | U7Y8SXOR | 5.045 ns | 0.0353 ns | 0.0330 ns | - |
| ISO/IEC 7064 MOD 1271-36 | U7Y8SXRC0FI | 7.174 ns | 0.0804 ns | 0.0713 ns | - |
| ISO/IEC 7064 MOD 1271-36 | U7Y8SXRC0O3SX4 | 9.202 ns | 0.0654 ns | 0.0580 ns | - |
| ISO/IEC 7064 MOD 1271-36 | U7Y8SXRC0O3SC4I9D | 11.000 ns | 0.0479 ns | 0.0424 ns | - |
| ISO/IEC 7064 MOD 1271-36 | U7Y8SXRC0O3SC4IHYQYI | 13.747 ns | 0.0482 ns | 0.0376 ns | - |
| ISO/IEC 7064 MOD 1271-36 | U7Y8SXRC0O3SC4IHYQF4M44 | 16.055 ns | 0.0694 ns | 0.0615 ns | - |
| ISO/IEC 7064 MOD 37-2 | U7YZ | 2.688 ns | 0.0120 ns | 0.0100 ns | - |
| ISO/IEC 7064 MOD 37-2 | U7Y8SXV | 4.350 ns | 0.0338 ns | 0.0299 ns | - |
| ISO/IEC 7064 MOD 37-2 | U7Y8SXRC0E | 5.145 ns | 0.0262 ns | 0.0245 ns | - |
| ISO/IEC 7064 MOD 37-2 | U7Y8SXRC0O3SU | 6.425 ns | 0.0441 ns | 0.0391 ns | - |
| ISO/IEC 7064 MOD 37-2 | U7Y8SXRC0O3SC4IB | 7.772 ns | 0.0609 ns | 0.0570 ns | - |
| ISO/IEC 7064 MOD 37-2 | U7Y8SXRC0O3SC4IHYQG | 9.111 ns | 0.0870 ns | 0.0813 ns | - |
| ISO/IEC 7064 MOD 37-2 | U7Y8SXRC0O3SC4IHYQF4MF | 10.416 ns | 0.1256 ns | 0.1113 ns | - |
| ISO/IEC 7064 MOD 37,36 | U7YW | 3.189 ns | 0.0284 ns | 0.0252 ns | - |
| ISO/IEC 7064 MOD 37,36 | U7Y8SX8 | 5.281 ns | 0.0747 ns | 0.0624 ns | - |
| ISO/IEC 7064 MOD 37,36 | U7Y8SXRC0E | 6.783 ns | 0.0679 ns | 0.0635 ns | - |
| ISO/IEC 7064 MOD 37,36 | U7Y8SXRC0O3SR | 8.329 ns | 0.0880 ns | 0.0780 ns | - |
| ISO/IEC 7064 MOD 37,36 | U7Y8SXRC0O3SC4IT | 9.865 ns | 0.1457 ns | 0.1292 ns | - |
| ISO/IEC 7064 MOD 37,36 | U7Y8SXRC0O3SC4IHYQD | 11.894 ns | 0.1117 ns | 0.0990 ns | - |
| ISO/IEC 7064 MOD 37,36 | U7Y8SXRC0O3SC4IHYQF4MP | 13.173 ns | 0.0399 ns | 0.0354 ns | - |
| NOID Check Digit | 11404/2h9m | 5.089 ns | 0.0247 ns | 0.0219 ns | - |
| NOID Check Digit | 11404/2h9tqb0 | 6.419 ns | 0.0417 ns | 0.0369 ns | - |
| NOID Check Digit | 11404/2h9tqbxk6d | 7.598 ns | 0.0334 ns | 0.0279 ns | - |
| NOID Check Digit | 11404/2h9tqbxk6rw74 | 8.816 ns | 0.0623 ns | 0.0552 ns | - |
| NOID Check Digit | 11404/2h9tqbxk6rw7dwmz | 10.007 ns | 0.0597 ns | 0.0466 ns | - |
Value Specific Algorithms
| Algorithm Name | Value | Mean | Error | StdDev | Allocated |
|---|---|---|---|---|---|
| ABA RTN | 111000025 | 4.572 ns | 0.0099 ns | 0.0088 ns | - |
| ABA RTN | 122235821 | 4.528 ns | 0.0049 ns | 0.0046 ns | - |
| ABA RTN | 325081403 | 4.526 ns | 0.0029 ns | 0.0022 ns | - |
| CUSIP | 37833100 | 6.268 ns | 0.0053 ns | 0.0049 ns | - |
| CUSIP | 38143VAA7 | 6.258 ns | 0.0057 ns | 0.0050 ns | - |
| CUSIP | 91282CJL6 | 6.258 ns | 0.0073 ns | 0.0065 ns | - |
| FIGI | BBG000B9Y5X2 | 7.885 ns | 0.0056 ns | 0.0050 ns | - |
| FIGI | BBG111111160 | 7.929 ns | 0.0053 ns | 0.0045 ns | - |
| FIGI | BBGZYXWVTSR7 | 8.047 ns | 0.0575 ns | 0.0537 ns | - |
| IBAN | BE71096123456769 | 11.903 ns | 0.0768 ns | 0.0718 ns | - |
| IBAN | GB82WEST12345698765432 | 21.263 ns | 0.2220 ns | 0.2076 ns | - |
| IBAN | SC74MCBL01031234567890123456USD | 32.737 ns | 0.3820 ns | 0.3190 ns | - |
| ICAO 9303 | U7Y5 | 4.432 ns | 0.0234 ns | 0.0182 ns | - |
| ICAO 9303 | U7Y8SX8 | 6.267 ns | 0.0501 ns | 0.0418 ns | - |
| ICAO 9303 | U7Y8SXRC03 | 8.173 ns | 0.0895 ns | 0.0794 ns | - |
| ICAO 9303 | U7Y8SXRC0O3S8 | 10.376 ns | 0.0802 ns | 0.0711 ns | - |
| ICAO 9303 | U7Y8SXRC0O3SC4I2 | 12.741 ns | 0.0879 ns | 0.0779 ns | - |
| ICAO 9303 | U7Y8SXRC0O3SC4IHYQ9 | 15.234 ns | 0.1390 ns | 0.1301 ns | - |
| ICAO 9303 | U7Y8SXRC0O3SC4IHYQF4M8 | 16.228 ns | 0.1301 ns | 0.1153 ns | - |
| ICAO 9303 Machine Readable Visa | I<UTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<br>D231458907UTO7408122F1204159<<<<<<<< | 19.925 ns | 0.0992 ns | 0.0928 ns | - |
| ICAO 9303 Machine Readable Visa | I<UTOSKYWALKER<<LUKE<<<<<<<<<<<<<<<<<br>STARWARS45UTO7705256M2405252<<<<<<<< | 20.552 ns | 0.1990 ns | 0.1862 ns | - |
| ICAO 9303 Machine Readable Visa | V<UTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<<br>L898902C<3UTO6908061F9406236ZE184226B<<<<<<< | 20.633 ns | 0.1249 ns | 0.1107 ns | - |
| ICAO 9303 Size TD1 | I<UTOD231458907<<<<<<<<<<<<<<<<br>7408122F1204159UTO<<<<<<<<<<<6<br>ERIKSSON<<ANNA<MARIA<<<<<<<<<< | 33.010 ns | 0.1887 ns | 0.1673 ns | - |
| ICAO 9303 Size TD1 | I<UTOSTARWARS45<<<<<<<<<<<<<<<<br>7705256M2405252UTO<<<<<<<<<<<4<br>SKYWALKER<<LUKE<<<<<<<<<<<<<<< | 39.914 ns | 0.3377 ns | 0.2994 ns | - |
| ICAO 9303 Size TD1 | I<UTOD23145890<AB112234566<<<<<br>7408122F1204159UTO<<<<<<<<<<<4<br>ERIKSSON<<ANNA<MARIA<<<<<<<<<< | 32.857 ns | 0.2455 ns | 0.2297 ns | - |
| ICAO 9303 Size TD2 | I<UTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<br>D231458907UTO7408122F1204159<<<<<<<6 | 32.312 ns | 0.2888 ns | 0.2702 ns | - |
| ICAO 9303 Size TD2 | I<UTOQWERTY<<ASDF<<<<<<<<<<<<<<<<<<<<br>D23145890<UTO7408122F1204159AB1124<4 | 33.326 ns | 0.2760 ns | 0.2581 ns | - |
| ICAO 9303 Size TD2 | I<UTOSKYWALKER<<LUKE<<<<<<<<<<<<<<<<<br>STARWARS45UTO7705256M2405252<<<<<<<8 | 32.079 ns | 0.3153 ns | 0.2950 ns | - |
| ICAO 9303 Size TD3 | P<UTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<<br>L898902C36UTO7408122F1204159ZE184226B<<<<<10 | 41.611 ns | 0.2497 ns | 0.2213 ns | - |
| ICAO 9303 Size TD3 | P<UTOQWERTY<<ASDF<<<<<<<<<<<<<<<<<<<<<<<<<<<<br>Q123987655UTO3311226F2010201<<<<<<<<<<<<<<06 | 41.648 ns | 0.3441 ns | 0.3219 ns | - |
| ICAO 9303 Size TD3 | P<UTOSKYWALKER<<LUKE<<<<<<<<<<<<<<<<<<<<<<<<<br>STARWARS45UTO7705256M2405252HAN<SHOT<FIRST78 | 41.434 ns | 0.3941 ns | 0.3686 ns | - |
| ISAN | C594660A8B2E5D22X6DDA3272E | 18.823 ns | 0.2636 ns | 0.2336 ns | - |
| ISAN | D02C42E954183EE2Q1291C8AEO | 17.367 ns | 0.1634 ns | 0.1364 ns | - |
| ISAN | E9530C32BC0EE83B269867B20F | 16.964 ns | 0.1627 ns | 0.1442 ns | - |
| ISAN (Formatted) | ISAN C594-660A-8B2E-5D22-X | 15.646 ns | 0.1663 ns | 0.1474 ns | - |
| ISAN (Formatted) | ISAN D02C-42E9-5418-3EE2-Q | 14.682 ns | 0.1183 ns | 0.1049 ns | - |
| ISAN (Formatted) | ISAN E953-0C32-BC0E-E83B-2 | 15.727 ns | 0.1711 ns | 0.1516 ns | - |
| ISAN (Formatted) | ISAN C594-660A-8B2E-5D22-X-6DDA-3272-E | 24.230 ns | 0.2041 ns | 0.1909 ns | - |
| ISAN (Formatted) | ISAN D02C-42E9-5418-3EE2-Q-1291-C8AE-O | 25.131 ns | 0.1821 ns | 0.1614 ns | - |
| ISAN (Formatted) | ISAN E953-0C32-BC0E-E83B-2-6986-7B20-F | 25.201 ns | 0.1258 ns | 0.1051 ns | - |
| ISIN | AU0000XVGZA3 | 7.816 ns | 0.0852 ns | 0.0797 ns | - |
| ISIN | GB0002634946 | 7.346 ns | 0.0458 ns | 0.0428 ns | - |
| ISIN | US0378331005 | 7.348 ns | 0.0563 ns | 0.0526 ns | - |
| ISO 6346 | CSQU3054383 | 7.957 ns | 0.0592 ns | 0.0554 ns | - |
| ISO 6346 | MSKU9070323 | 7.953 ns | 0.0625 ns | 0.0554 ns | - |
| ISO 6346 | TOLU4734787 | 7.950 ns | 0.0467 ns | 0.0437 ns | - |
| NHS | 4505577104 | 4.584 ns | 0.0319 ns | 0.0298 ns | - |
| NHS | 5301194917 | 4.577 ns | 0.0302 ns | 0.0268 ns | - |
| NHS | 9434765919 | 4.574 ns | 0.0262 ns | 0.0245 ns | - |
| NPI | 1122337797 | 6.099 ns | 0.0248 ns | 0.0232 ns | - |
| NPI | 1234567893 | 6.748 ns | 0.0648 ns | 0.0574 ns | - |
| NPI | 1245319599 | 6.038 ns | 0.0320 ns | 0.0267 ns | - |
| SEDOL | 3134865 | 5.849 ns | 0.0271 ns | 0.0240 ns | - |
| SEDOL | B0YQ5W0 | 5.872 ns | 0.0328 ns | 0.0291 ns | - |
| SEDOL | BRDVMH9 | 5.860 ns | 0.0361 ns | 0.0302 ns | - |
| VIN | 1G8ZG127XWZ157259 | 13.278 ns | 0.0645 ns | 0.0538 ns | - |
| VIN | 1HGEM21292L047875 | 13.297 ns | 0.0520 ns | 0.0434 ns | - |
| VIN | 1M8GDM9AXKP042788 | 12.869 ns | 0.0624 ns | 0.0521 ns | - |
Damm Custom Quasigroup Algorithm
Note: The Order 10 quasigroup class used in the benchmarks is the one used as an example for IDammQuasigroup. The Order 16 quasigroup class used in the benchmarks is the one used as an example for DammCustomQuasigroup.
| Algorithm Name | Value | Mean | Error | StdDev | Allocated |
|---|---|---|---|---|---|
| Damm Custom Quasigroup (Order = 10) | 1402 | 4.376 ns | 0.0415 ns | 0.0388 ns | - |
| Damm Custom Quasigroup (Order = 10) | 1406622 | 6.009 ns | 0.0477 ns | 0.0423 ns | - |
| Damm Custom Quasigroup (Order = 10) | 1406625388 | 8.883 ns | 0.0455 ns | 0.0380 ns | - |
| Damm Custom Quasigroup (Order = 10) | 1406625380422 | 12.916 ns | 0.0845 ns | 0.0705 ns | - |
| Damm Custom Quasigroup (Order = 10) | 1406625380425518 | 16.306 ns | 0.0612 ns | 0.0511 ns | - |
| Damm Custom Quasigroup (Order = 10) | 1406625380425510280 | 19.675 ns | 0.0967 ns | 0.0904 ns | - |
| Damm Custom Quasigroup (Order = 10) | 1406625380425510282654 | 23.083 ns | 0.1054 ns | 0.0934 ns | - |
| Damm Custom Quasigroup (Order = 16) | 2ED1 | 7.643 ns | 0.0659 ns | 0.0551 ns | - |
| Damm Custom Quasigroup (Order = 16) | 2EDC15F | 12.152 ns | 0.0961 ns | 0.0852 ns | - |
| Damm Custom Quasigroup (Order = 16) | 2EDC15B3C5 | 16.691 ns | 0.1784 ns | 0.1489 ns | - |
| Damm Custom Quasigroup (Order = 16) | 2EDC15B3C1C33 | 21.793 ns | 0.1751 ns | 0.1552 ns | - |
| Damm Custom Quasigroup (Order = 16) | 2EDC15B3C1C34F46 | 26.625 ns | 0.1694 ns | 0.1502 ns | - |
| Damm Custom Quasigroup (Order = 16) | 2EDC15B3C1C34F4DA52 | 31.997 ns | 0.3190 ns | 0.2828 ns | - |
| Damm Custom Quasigroup (Order = 16) | 2EDC15B3C1C34F4DA55F37 | 36.635 ns | 0.3529 ns | 0.3301 ns | - |
Validate Method (with ICheckDigitMask)
The following implementation of ICheckDigitMask is used for the benchmarks:
public class GroupsOfThreeCheckDigitMask : ICheckDigitMask
{
public Boolean ExcludeCharacter(Int32 index) => (index + 1) % 4 == 0;
public Boolean IncludeCharacter(Int32 index) => (index + 1) % 4 != 0;
}
General Numeric Algorithms
| Algorithm Name | Value | Mean | Error | StdDev | Allocated |
|---|---|---|---|---|---|
| Damm | 140 2 | 4.625 ns | 0.1064 ns | 0.0996 ns | - |
| Damm | 140 662 2 | 6.415 ns | 0.1434 ns | 0.2056 ns | - |
| Damm | 140 662 538 8 | 8.091 ns | 0.0660 ns | 0.0585 ns | - |
| Damm | 140 662 538 042 2 | 9.891 ns | 0.1324 ns | 0.1106 ns | - |
| Damm | 140 662 538 042 551 8 | 12.687 ns | 0.1039 ns | 0.0971 ns | - |
| Damm | 140 662 538 042 551 028 0 | 16.170 ns | 0.3044 ns | 0.2848 ns | - |
| Damm | 140 662 538 042 551 028 265 4 | 19.209 ns | 0.2492 ns | 0.2331 ns | - |
| Luhn | 140 4 | 4.647 ns | 0.0278 ns | 0.0232 ns | - |
| Luhn | 140 662 8 | 6.048 ns | 0.0490 ns | 0.0458 ns | - |
| Luhn | 140 662 538 2 | 8.229 ns | 0.0595 ns | 0.0528 ns | - |
| Luhn | 140 662 538 042 1 | 9.500 ns | 0.0665 ns | 0.0622 ns | - |
| Luhn | 140 662 538 042 551 4 | 11.272 ns | 0.0564 ns | 0.0528 ns | - |
| Luhn | 140 662 538 042 551 028 5 | 13.034 ns | 0.0692 ns | 0.0613 ns | - |
| Luhn | 140 662 538 042 551 028 265 1 | 14.754 ns | 0.1212 ns | 0.1075 ns | - |
| Modulus10_13 | 140 3 | 4.536 ns | 0.0544 ns | 0.0509 ns | - |
| Modulus10_13 | 140 662 7 | 5.908 ns | 0.1229 ns | 0.1090 ns | - |
| Modulus10_13 | 140 662 538 5 | 7.526 ns | 0.0957 ns | 0.0895 ns | - |
| Modulus10_13 | 140 662 538 042 5 | 9.083 ns | 0.1075 ns | 0.0898 ns | - |
| Modulus10_13 | 140 662 538 042 551 8 | 10.977 ns | 0.1084 ns | 0.1014 ns | - |
| Modulus10_13 | 140 662 538 042 551 028 8 | 12.475 ns | 0.1031 ns | 0.0965 ns | - |
| Modulus10_13 | 140 662 538 042 551 028 265 7 | 14.315 ns | 0.1808 ns | 0.1691 ns | - |
| Modulus10_1 | 140 1 | 4.231 ns | 0.0572 ns | 0.0535 ns | - |
| Modulus10_1 | 140 662 8 | 5.225 ns | 0.0514 ns | 0.0481 ns | - |
| Modulus10_1 | 140 662 538 4 | 6.567 ns | 0.0868 ns | 0.0812 ns | - |
| Modulus10_2 | 140 6 | 4.208 ns | 0.0254 ns | 0.0225 ns | - |
| Modulus10_2 | 140 662 7 | 5.323 ns | 0.0723 ns | 0.0676 ns | - |
| Modulus10_2 | 140 662 538 9 | 7.141 ns | 0.0285 ns | 0.0267 ns | - |
| Modulus11_27Decimal | 140 6 | 4.353 ns | 0.0255 ns | 0.0213 ns | - |
| Modulus11_27Decimal | 140 662 0 | 6.006 ns | 0.0760 ns | 0.0711 ns | - |
| Modulus11_27Decimal | 140 662 538 5 | 7.363 ns | 0.0624 ns | 0.0521 ns | - |
| Modulus11_27Decimal | 140 662 538 042 1 | 9.900 ns | 0.2009 ns | 0.1880 ns | - |
| Modulus11_27Decimal | 140 662 538 042 551 0 | 11.595 ns | 0.0500 ns | 0.0417 ns | - |
| Modulus11_27Decimal | 140 662 538 042 551 028 8 | 12.468 ns | 0.1190 ns | 0.1055 ns | - |
| Modulus11_27Decimal | 140 662 538 042 551 028 265 0 | 14.361 ns | 0.0864 ns | 0.0808 ns | - |
| Modulus11_27Extended | 140 6 | 4.445 ns | 0.0202 ns | 0.0179 ns | - |
| Modulus11_27Extended | 140 662 0 | 5.954 ns | 0.0248 ns | 0.0220 ns | - |
| Modulus11_27Extended | 140 662 538 5 | 7.632 ns | 0.0815 ns | 0.0723 ns | - |
| Modulus11_27Extended | 140 662 538 042 1 | 9.070 ns | 0.0376 ns | 0.0352 ns | - |
| Modulus11_27Extended | 140 662 538 042 551 0 | 10.724 ns | 0.0461 ns | 0.0385 ns | - |
| Modulus11_27Extended | 140 662 538 042 551 028 8 | 12.649 ns | 0.2177 ns | 0.2036 ns | - |
| Modulus11_27Extended | 140 662 538 042 551 028 265 0 | 14.339 ns | 0.2057 ns | 0.1824 ns | - |
| Modulus11Decimal | 140 6 | 4.200 ns | 0.0472 ns | 0.0442 ns | - |
| Modulus11Decimal | 140 662 0 | 5.134 ns | 0.0596 ns | 0.0529 ns | - |
| Modulus11Decimal | 140 662 538 8 | 6.342 ns | 0.0429 ns | 0.0401 ns | - |
| Modulus11Extended | 140 6 | 4.317 ns | 0.0073 ns | 0.0068 ns | - |
| Modulus11Extended | 140 662 0 | 5.268 ns | 0.0358 ns | 0.0335 ns | - |
| Modulus11Extended | 140 662 538 8 | 6.603 ns | 0.0696 ns | 0.0651 ns | - |
| Verhoeff | 140 1 | 5.549 ns | 0.0181 ns | 0.0151 ns | - |
| Verhoeff | 140 662 5 | 8.417 ns | 0.0464 ns | 0.0434 ns | - |
| Verhoeff | 140 662 538 8 | 11.810 ns | 0.0828 ns | 0.0734 ns | - |
| Verhoeff | 140 662 538 042 6 | 15.582 ns | 0.0920 ns | 0.0768 ns | - |
| Verhoeff | 140 662 538 042 551 2 | 19.340 ns | 0.0857 ns | 0.0760 ns | - |
| Verhoeff | 140 662 538 042 551 028 5 | 23.305 ns | 0.1805 ns | 0.1600 ns | - |
| Verhoeff | 140 662 538 042 551 028 265 5 | 27.167 ns | 0.0691 ns | 0.0647 ns | - |
Damm Custom Quasigroup Algorithm
Note: The Order 10 quasigroup class used in the benchmarks is the one used as an example for IDammQuasigroup. The Order 16 quasigroup class used in the benchmarks is the one used as an example for DammCustomQuasigroup.
| Algorithm Name | Value | Mean | Error | StdDev | Allocated |
|---|---|---|---|---|---|
| Damm Custom Quasigroup (Order = 10) | 140 2 | 5.523 ns | 0.1265 ns | 0.1600 ns | - |
| Damm Custom Quasigroup (Order = 10) | 140 662 2 | 7.395 ns | 0.0553 ns | 0.0490 ns | - |
| Damm Custom Quasigroup (Order = 10) | 140 662 538 8 | 9.303 ns | 0.0722 ns | 0.0640 ns | - |
| Damm Custom Quasigroup (Order = 10) | 140 662 538 042 2 | 11.906 ns | 0.0845 ns | 0.0791 ns | - |
| Damm Custom Quasigroup (Order = 10) | 140 662 538 042 551 8 | 15.443 ns | 0.1506 ns | 0.1409 ns | - |
| Damm Custom Quasigroup (Order = 10) | 140 662 538 042 551 028 0 | 18.744 ns | 0.1593 ns | 0.1490 ns | - |
| Damm Custom Quasigroup (Order = 10) | 140 662 538 042 551 028 265 4 | 21.765 ns | 0.1053 ns | 0.0985 ns | - |
| Damm Custom Quasigroup (Order = 16) | 2ED 1 | 9.415 ns | 0.1854 ns | 0.2061 ns | - |
| Damm Custom Quasigroup (Order = 16) | 2ED C15 F | 14.429 ns | 0.1800 ns | 0.1684 ns | - |
| Damm Custom Quasigroup (Order = 16) | 2ED C15 B3C 5 | 19.850 ns | 0.2397 ns | 0.2242 ns | - |
| Damm Custom Quasigroup (Order = 16) | 2ED C15 B3C 1C3 3 | 24.856 ns | 0.5198 ns | 0.5986 ns | - |
| Damm Custom Quasigroup (Order = 16) | 2ED C15 B3C 1C3 4F4 6 | 30.127 ns | 0.3615 ns | 0.3381 ns | - |
| Damm Custom Quasigroup (Order = 16) | 2ED C15 B3C 1C3 4F4 DA5 2 | 35.560 ns | 0.4475 ns | 0.3737 ns | - |
| Damm Custom Quasigroup (Order = 16) | 2ED C15 B3C 1C3 4F4 DA5 5F3 7 | 40.733 ns | 0.4758 ns | 0.4451 ns | - |
Release History/Release Notes
v1.0.0-alpha
Initial limited release. Included algorithms:
- ABA RTN (Routing Transit Number) Algorithm
- Damm Algorithm
- ISIN (International Securities Identification Number) Algorithm
- Luhn Algorithm
- Modulus10_1 Algorithm
- Modulus10_2 Algorithm
- Modulus10_13 Algorithm (UPC/EAN/ISBN-13/etc.)
- Modulus11 Algorithm (ISBN-10/ISSN/etc.)
- NHS (UK National Health Service) Algorithm
- NPI (US National Provider Identifier) Algorithm
- Verhoeff Algorithm
- VIN (Vehicle Identification Number) Algorithm
v1.0.0
Initial release. Additional included algorithms:
- ISO/IEC 7064 MOD 11,10
- ISO/IEC 7064 MOD 11-2
- ISO/IEC 7064 MOD 1271-36
- ISO/IEC 7064 MOD 27,26
- ISO/IEC 7064 MOD 37-2
- ISO/IEC 7064 MOD 37,36
- ISO/IEC 7064 MOD 661-26
- ISO/IEC 7064 MOD 97-10
v1.1.0
Additional included algorithms:
- AlphanumericMod97_10Algorithm
- IbanAlgorithm
- IsanAlgorithm (including ValidateFormatted method)
- NcdAlgorithm (NOID Check Digit)
Performance increases for:
- ISO/IEC 7064 MOD 1271-36, Validate method ~18% improvement
- ISO/IEC 7064 MOD 37-2, Validate method ~17% improvement, TryCalculateCheckDigit method ~20% improvement
- ISO/IEC 7064 MOD 37-36, Validate method ~18% improvement, TryCalculateCheckDigit method ~21% improvement
v2.0.0
Updated to .Net 8.0
Average performance improvement for .Net 8.0 across all algorithms: Validate method ~8% improvement, TryCalculateCheckDigit method ~4.9% improvement
Detailed benchmark results for .Net 7 vs .Net 8 located at https://github.com/KnowledgeForwardSolutions/CheckDigits.Net/blob/main/Documentation/DotNet7_DotNet8_PerformanceComparision.md
v2.1.0
Additional included algorithms:
- CUSIP Algorithm
- ISO 6346 Algorithm
- SEDOL Algorithm
Performance increases for:
- Luhn Algorithm, Validate method ~15% improvement over .Net 7, TryCalculateCheckDigit method ~27% improvement over .Net 7 (Luhn algorithm originally saw a slight performance decrease when switching from .Net 7 to .Net 8. This release addresses that performance decrease.)
- Damm Algorithm, Validate and TryCalculateCheckDigit methods ~30% improvement
- Verhoeff Algorithm, Validate method ~20% improvement, TryCalculateCheckDigit method ~30% improvement
v2.2.0
Support for netstandard2.0
Thanks to Steff Beckers for this addition
v2.3.0
Additional included algorithms:
- FIGI Algorithm
- ICAO Algorithm
- ICAO 9303 Document Size TD1 Algorithm
- ICAO 9303 Document Size TD2 Algorithm
- ICAO 9303 Document Size TD3 Algorithm
- ICAO 9303 Machine Readable Visa Algorithm
Performance increases for:
- AlphanumericMod97_10Algorithm, Validate method ~15% improvement, TryCalculateCheckDigits method ~8% improvement
- IBAN Algorithm, Validate method ~8% improvement
- ISIN algorithm, ~9% improvement for Validate and TryCalculateCheckDigit methods
- ISO/IEC 7064 MOD 1271-36, TryCalculateCheckDigits method ~8% improvement
- NcdAlgorithm (NOID Check Digit), minimum 10% improvement for Validate method, improvement increases with length of value.
- NpiAlgorithm, Validate method ~8% improvement
v2.3.1
Documentation update. Fix several minor documentation errors in README file. No code changes.
v3.0.0
Updated to .Net 10.0
Average performance improvement for .Net 10.0 across all algorithms is ~4% for both Validate and TryCalculateCheckDigit methods.
Detailed benchmark results for .Net 8 vs .Net 10 located at https://github.com/KnowledgeForwardSolutions/CheckDigits.Net/blob/main/Documentation/DotNet8_DotNet10_PerformanceComparision.md
Added masked validation support for algorithms via ICheckDigitMask and IMaskedCheckDigitAlgorithm interfaces. Algorithms that implement IMaskedCheckDigitAlgorithm:
- Luhn Algorithm
v3.1.0
Additional included algorithms:
- Modulus11Decimal Algorithm
- Modulus11Extended Algorithm
- Modulus11_27Decimal Algorithm
- Modulus11_27Extended Algorithm
- DammCustomQuasigroup Algorithm
Added masked validation support to the following algorithms:
- AlphanumericMod97_10 Algorithm
- Damm Algorithm
- Modulus10_1 Algorithm
- Modulus10_13 Algorithm
- Modulus10_2 Algorithm
- Verhoeff Algorithm
Minor updates to the following algorithms:
- ICAO 9303 Document Size TD1 Algorithm
- ICAO 9303 Document Size TD2 Algorithm
- ICAO 9303 Document Size TD3 Algorithm
- ICAO 9303 Machine Readable Visa Algorithm
The original implementation of the above algorithms allowed alphabetic characters in the date of birth/expiration date fields as long as the check digit(s) were valid for the characters used. The updated implementation only allows numeric characters in those fields, which is consistent with the ICAO 9303 specification.
Additionally, the LineSeparator property of the above algorithms was marked Obsolete and will be removed in a future release. Instead, the separator used between lines in the MRZ is inferred from the length of the value being validated.
Algorithms marked as Obsolete:
- Modulus11 Algorithm (ISBN-10/ISSN/etc.) - Replaced by the Modulus11Extended algorithm.
- NHS (UK National Health Service) Algorithm - Replaced by the Modulus11_27Decimal algorithm.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- IndexRange (>= 1.1.0)
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
NuGet packages (2)
Showing the top 2 NuGet packages that depend on CheckDigits.Net:
| Package | Downloads |
|---|---|
|
CheckDigits.Net.FluentValidation
CheckDigits.Net.FluentValidation integrates CheckDigits.Net with FluentValidation and supports adding check digit validation in your validation classes. |
|
|
CheckDigits.Net.DataAnnotations
CheckDigits.Net.Annotations extends CheckDigits.Net and provides custom DataAnnotation classes for validating that a string property includes a valid check digit according to a wide variety of check digit algorithms. |
GitHub repositories
This package is not used by any popular GitHub repositories.
## 1.0.0-alpha
Initial limited release. Included algorithms:
* ABA RTN (Routing Transit Number) Algorithm
* Damm Algorithm
* ISIN (International Securities Identification Number) Algorithm
* Luhn Algorithm
* Modulus10_1 Algorithm
* Modulus10_2 Algorithm
* Modulus10_13 Algorithm (UPC/EAN/ISBN-13/etc.)
* Modulus11 Algorithm (ISBN-10/ISSN/etc.)
* NHS (UK National Health Service) Algorithm
* NPI (US National Provider Identifier) Algorithm
* Verhoeff Algorithm
* VIN (Vehicle Identification Number) Algorithm
## 1.0.0
Initial release. Additional included algorithms
* ISO/IEC 7064 MOD 11,10
* ISO/IEC 7064 MOD 11-2
* ISO/IEC 7064 MOD 1271-36
* ISO/IEC 7064 MOD 27,26
* ISO/IEC 7064 MOD 37-2
* ISO/IEC 7064 MOD 37,36
* ISO/IEC 7064 MOD 661-26
* ISO/IEC 7064 MOD 97-10
## v1.1.0
Additional included algorithms
* AlphanumericMod97_10Algorithm
* IbanAlgorithm
* IsanAlgorithm (including ValidateFormatted method)
* NcdAlgorithm (NOID Check Digit)
Performance increases for:
* ISO/IEC 7064 MOD 1271-36, Validate method ~18% improvement
* ISO/IEC 7064 MOD 37-2, Validate method ~17% improvement, TryCalculateCheckDigit method ~20% improvement
* ISO/IEC 7064 MOD 37-36, Validate method ~18% improvement, TryCalculateCheckDigit method ~21% improvement
## v2.0.0
Updated to .Net 8.0
Average performance improvement for .Net 8.0 across all algorithms:
Validate method ~8% improvement, TryCalculateCheckDigit method ~4.9% improvement
## v2.1.0
Additional included algorithms
* CUSIP Algorithm
* ISO 6346 Algorithm
* SEDOL Algorithm
Performance increases for:
* Luhn Algorithm, Validate method ~15% improvement over .Net 7, TryCalculateCheckDigit method ~27% improvement over .Net 7
(Luhn algorithm originally saw a slight performance decrease when switching from .Net 7 to .Net 8. This release addresses that performance decrease.)
* Damm Algorithm, Validate and TryCalculateCheckDigit methods ~30% improvement
* Verhoeff Algorithm, Validate method ~20% improvement, TryCalculateCheckDigit method ~30% improvement
## v2.2.0
Support for netstandard2.0
Thanks to Steff Beckers for this addition
## v2.3.0
Additional included algorithms
* FIGI Algorithm
* ICAO Algorithm
* ICAO 9303 Document Size TD1 Algorithm
* ICAO 9303 Document Size TD2 Algorithm
* ICAO 9303 Document Size TD3 Algorithm
* ICAO 9303 Machine Readable Visa Algorithm
Performance increases for:
* AlphanumericMod97_10Algorithm, Validate method ~15% improvement, TryCalculateCheckDigits method ~8% improvement
* IBAN Algorithm, Validate method ~8% improvement
* ISIN algorithm, ~9% improvement for Validate and TryCalculateCheckDigit methods
* ISO/IEC 7064 MOD 1271-36, TryCalculateCheckDigits method ~8% improvement
* NcdAlgorithm (NOID Check Digit), minimum 10% improvement for Validate method, improvement increases with length of value.
* NpiAlgorithm, Validate method ~8 improvement
## v2.3.1
Documentation update. Fix several minor documentation errors in README file. No code changes.
## v3.0.0
Updated to .Net 10.0
Average performance improvement for .Net 10.0 across all algorithms is ~4% for
both Validate and TryCalculateCheckDigit methods.
Detailed benchmark results for .Net 8 vs .Net 10 located at https://github.com/KnowledgeForwardSolutions/CheckDigits.Net/blob/main/Documentation/DotNet8_DotNet10_PerformanceComparision.md
Added masked validation support for algorithms via ICheckDigitMask and IMaskedCheckDigitAlgorithm interfaces. Algorithms that implement IMaskedCheckDigitAlgorithm:
* Luhn Algorithm
## v3.1.0
Additional included algorithms:
* Modulus11Decimal Algorithm
* Modulus11Extended Algorithm
* Modulus11_27Decimal Algorithm
* Modulus11_27Extended Algorithm
* DammCustomQuasigroup Algorithm
Added masked validation support to the following algorithms:
* AlphanumericMod97_10 Algorithm
* Damm Algorithm
* Modulus10_1 Algorithm
* Modulus10_13 Algorithm
* Modulus10_2 Algorithm
* Verhoeff Algorithm
Minor updates to the following algorithms:
* ICAO 9303 Document Size TD1 Algorithm
* ICAO 9303 Document Size TD2 Algorithm
* ICAO 9303 Document Size TD3 Algorithm
* ICAO 9303 Machine Readable Visa Algorithm
The original implementation of the above algorithms allowed alphabetic characters in the date of birth/expiration date fields
as long as the check digit(s) were valid for the characters used. The updated implementation only allows numeric characters
in those fields, which is consistent with the ICAO 9303 specification.
Additionally, the LineSeparator property of the above algorithms was marked Obsolete and will be removed in a future release.
Instead, the separator used between lines in the MRZ is inferred from the length of the value being validated.
Algorithms marked as Obsolete:
* Modulus11 Algorithm (ISBN-10/ISSN/etc.) - Replaced by the Modulus11Extended algorithm.
* NHS (UK National Health Service) Algorithm - Replaced by the Modulus11_27Decimal algorithm.