Created by the german IBM scientist Hans Peter Luhn, the Luhn Algorithm is a checksum formula being used to validate a variety of identification numbers, such as credit card numbers, IMEI numbers etc.
In this blog post, I will show you some functions I created that uses this algorithm. It can be used to calculate a checksum digit from a number, as well as validate numbers using the Luhn Algorithm checksum validation.
First off we have the main function, Get-LuhnChecksum. This function takes a number (uint64) as input and calculates the Luch checksum. This checksum is then used by either New-LuhnChecksumDigit to get the checksum digit of a number, or by Test-IsLuhnValid to validate a number, such as a credit card number.
Let’s demonstrate. We start off with a random number; 387234876. Let’s calculate the Luhn checksum digit for this number:
As you see, the result is 2. This is our checksum digit. We append this number to the end of our original number, so we now have 3872348762. We can further validate this number:
There you go. We have created a number with a Luhn checksum digit (last digit), and we have the means to validate it to see that it correct.
As stated earlier, this algorithm can be used to validate credit card numbers. It will detect any single digit error as well as almost all transpositions of adjacent digits. But since it’s not perfect, if you need credit card number validations you should add additional checks (such as number length).
Enjoy. If you have any questions, suggestions or bug-reports, please let me know in the comments section below (or on Twitter).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Get-LuhnChecksum { | |
<# | |
.SYNOPSIS | |
Calculate the Luhn checksum of a number. | |
.DESCRIPTION | |
The Luhn algorithm or Luhn formula, also known as the "modulus 10" or "mod 10" algorithm, | |
is a simple checksum formula used to validate a variety of identification numbers, such as | |
credit card numbers, IMEI numbers, National Provider Identifier numbers in the US, and | |
Canadian Social Insurance Numbers. It was created by IBM scientist Hans Peter Luhn. | |
.EXAMPLE | |
Get-LuhnChecksum -Number 1234567890123452 | |
Calculate the Luch checksum of the number. The result should be 60. | |
.INPUTS | |
System.UInt64 | |
.NOTES | |
Author: Øyvind Kallstad | |
Date: 19.02.2016 | |
Version: 1.0 | |
Dependencies: ConvertTo-Digits | |
.LINKS | |
https://en.wikipedia.org/wiki/Luhn_algorithm | |
https://communary.wordpress.com/ | |
https://github.com/gravejester/Communary.ToolBox | |
#> | |
[CmdletBinding()] | |
param ( | |
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] | |
[ValidateNotNullOrEmpty()] | |
[uint64] $Number | |
) | |
$digitsArray = ConvertTo-Digits –Number $Number | |
[array]::Reverse($digitsArray) | |
$sum = 0 | |
$index = 0 | |
foreach ($digit in $digitsArray) { | |
if (($index % 2) -eq 0) { | |
$doubledDigit = $digit * 2 | |
if (-not($doubledDigit -eq 0)) { | |
$doubleDigitArray = ConvertTo-Digits –Number $doubledDigit | |
$sum += ($doubleDigitArray | Measure-Object –Sum | Select-Object –ExpandProperty Sum) | |
} | |
} | |
else { | |
$sum += $digit | |
} | |
$index++ | |
} | |
Write-Output $sum | |
} | |
function New-LuhnChecksumDigit { | |
<# | |
.SYNOPSIS | |
Calculate the Luhn checksum digit for a number. | |
.DESCRIPTION | |
This function uses the Luhn algorithm to calculate the | |
Luhn checksum digit for a (partial) number. | |
.EXAMPLE | |
New-LuhnChecksumDigit -PartialNumber 123456789012345 | |
This will get the checksum digit for the number. The result should be 2. | |
.INPUTS | |
System.UInt64 | |
.NOTES | |
Author: Øyvind Kallstad | |
Date: 19.02.2016 | |
Version: 1.0 | |
Dependencies: Get-LuhnCheckSum | |
.LINKS | |
https://en.wikipedia.org/wiki/Luhn_algorithm | |
https://communary.wordpress.com/ | |
https://github.com/gravejester/Communary.ToolBox | |
#> | |
[CmdletBinding()] | |
param ( | |
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] | |
[uint64] $PartialNumber | |
) | |
$checksum = Get-LuhnCheckSum –Number $PartialNumber | |
Write-Output (($checksum * 9) % 10) | |
} | |
function Test-IsLuhnValid { | |
<# | |
.SYNOPSIS | |
Valdidate a number based on the Luhn Algorithm. | |
.DESCRIPTION | |
This function uses the Luhn algorithm to validate a number that includes | |
the Luhn checksum digit. | |
.EXAMPLE | |
Test-IsLuhnValid -Number 1234567890123452 | |
This will validate whether the number is valid according to the Luhn Algorithm. | |
.INPUTS | |
System.UInt64 | |
.OUTPUTS | |
System.Boolean | |
.NOTES | |
Author: Øyvind Kallstad | |
Date: 19.02.2016 | |
Version: 1.0 | |
Dependencies: Get-LuhnCheckSum, ConvertTo-Digits | |
.LINKS | |
https://en.wikipedia.org/wiki/Luhn_algorithm | |
https://communary.wordpress.com/ | |
https://github.com/gravejester/Communary.ToolBox | |
#> | |
[CmdletBinding()] | |
param ( | |
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] | |
[uint64] $Number | |
) | |
$numberDigits = ConvertTo-Digits –Number $Number | |
$checksumDigit = $numberDigits[-1] | |
$numberWithoutChecksumDigit = $numberDigits[0..($numberDigits.Count – 2)] -join '' | |
$checksum = Get-LuhnCheckSum –Number $numberWithoutChecksumDigit | |
if ((($checksum + $checksumDigit) % 10) -eq 0) { | |
Write-Output $true | |
} | |
else { | |
Write-Output $false | |
} | |
} |
Oh.. and you need this helper-function as well:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function ConvertTo-Digits { | |
<# | |
.SYNOPSIS | |
Convert an integer into an array of bytes of its individual digits. | |
.DESCRIPTION | |
Convert an integer into an array of bytes of its individual digits. | |
.EXAMPLE | |
ConvertTo-Digits 145 | |
.INPUTS | |
System.UInt64 | |
.LINK | |
https://communary.wordpress.com/ | |
https://github.com/gravejester/Communary.ToolBox | |
.NOTES | |
Author: Øyvind Kallstad | |
Date: 09.05.2015 | |
Version: 1.0 | |
#> | |
[OutputType([System.Byte[]])] | |
[CmdletBinding()] | |
param( | |
[Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] | |
[uint64]$Number | |
) | |
$n = $Number | |
$numberOfDigits = 1 + [convert]::ToUInt64([math]::Floor(([math]::Log10($n)))) | |
$digits = New-Object Byte[] $numberOfDigits | |
for ($i = ($numberOfDigits – 1); $i -ge 0; $i—) { | |
$digit = $n % 10 | |
$digits[$i] = $digit | |
$n = [math]::Floor($n / 10) | |
} | |
Write-Output $digits | |
} |
One comment