Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Country-specific checksums #39

Open
globalcitizen opened this issue Jan 22, 2016 · 50 comments
Open

Country-specific checksums #39

globalcitizen opened this issue Jan 22, 2016 · 50 comments

Comments

@globalcitizen
Copy link
Owner

We could support the calculation of known national (BBAN-level) or bank-specific (sub-BBAN-level) checksums against algorithms where known. Please contribute if you know any.

@globalcitizen
Copy link
Owner Author

globalcitizen commented Jan 28, 2016

Fun, fun, fun

Zero or more checksum digits
In some cases like the Netherlands (and perhaps French SIREN), there are no checksum digits but an algorithm exists anyway. About half of the countries have 1 checksum digit, and about half have 2.

Types of algorithms
In some cases like Spain, we see a single check digit applied to part of the BBAN, and a second check digit applied to the rest of the BBAN.

Normally however, the checksum should be applied to the whole BBAN minus the checksum itself, or possibly with the checksum zeroed (where this is significant) or the checksum replaced with 'XX' (where this is logical).

Newer countries almost certainly use an ISO7064 variant. Unfortunately, the ISO insists on charging for its standards, so we can't get a copy. In addition, there are actually two ISO7064 standards, a 1983 version and a 2003 version. Probably the older countries use the 1983 version. What differences exist are unclear. If someone would like to donate me copies of either standard, that would be useful. According to the ISO7064 java library, ISO7064 defines the following 'pure' systems, each of which use a single modulus for all stages of the calculation:

  • ISO/IEC 7064, MOD 11-2 for numeric strings with one check digit or the supplementary check character "X"
  • ISO/IEC 7064, MOD 37-2 for alphanumeric strings with one check digit or letter or the supplementary check character "*"
  • ISO/IEC 7064, MOD 97-10 for numeric strings with two check digits
  • ISO/IEC 7064, MOD 661-26 for alphabetic strings with two check letters
  • ISO/IEC 7064, MOD 1271-36 for alphanumeric strings with two check digits or letters

In addition, it also defines the following 'hybrid' systems (not implemented by the library). The hybrid systems each use two moduli in the calculation. One modulus is equal to, and the other is one greater than, the number of characters in the character set of the string to be protected. These hybrid systems always provide a check character within the character set of the string to be protected:

  • ISO/IEC 7064, MOD 11,10 for numeric strings with one check digit
  • ISO/IEC 7064, MOD 27,26 for alphabetic strings with one check letter
  • ISO/IEC 7064, MOD 37,36 for alphanumeric strings with one check digit or letter

There are also three other major algorithms:

  • Luhn algorithm (1954) - for numeric strings with one check digit, based on mod10
  • Verhoeff algorithm (1969) - for numeric strings with one check digit, complex, based on lookup tables
  • Damm algorithm (2004) - for numeric strings with one check digit, complex and rare, based on weakly totally anti-symmetric quasigroups.

Summary of Algorithms

Algorithm Input type Output characters Basis References Comments
ISO/IEC 7064, MOD 11-2 Numeric 1 digit/X Mod11 Radix 2 java
ISO/IEC 7064, MOD 37-2 Alphanumeric 1 digit/letter/* Mod37 Radix 2 java
ISO/IEC 7064, MOD 97-10 Numeric 2 digits Mod97 Radix 10 java
ISO/IEC 7064, MOD 661-26 Alphabetic 2 letters Mod661 Radix 26 java Unlikely.
ISO/IEC 7064, MOD 1271-36 Alphanumeric 2 digits or letters Mod 1271 Radix 36 java
ISO/IEC 7064, MOD 11,10 Numeric 1 digit Hybrid
ISO/IEC 7064, MOD 27,26 Alphabetic 1 letter Hybrid Unlikely
ISO/IEC 7064, MOD 37,36 Alphanumeric 1 digit/letter Hybrid
Luhn Numeric 1 digit Mod10
Verhoeff Numeric 1 digit Complex
Damm Numeric 1 digit Complex

Automation
Which system is in use should be possible to determine even without offficial documentation through reverse engineering given a sufficient number of real world account number examples. So, please contribute real world example BBANs for each of these countries.

I am working on developing a utility to automatically construct various inputs to various algorithms and test them for a given IBAN. This should help us to detect the correct implementation for new countries. The properties of a given country's input that can be automatically determined are:

  • Number of output check digits/characters (0, 1 or 2)
  • Check digits (0-9 only) or check characters? (ie. may include X or A-Z)
  • The various potential inputs (bank/branch portion, account portion), with checksum places removed or zeroed

So far I have ported the Java implementation to PHP using code generation, gathered working implementations of the final three algorithms, and written a general testing utility.

Countries with apparent national checksum systems

Data here is combined from Wikipedia, SWIFT official registry sources, random code and hearsay. We are looking to get solid references wherever possible, and in other cases to validate by reverse engineering a sufficient number of BBANs.

Country IBAN Format (x=checksum) Digits Algorithm References Done
Albania ALkk bbbs sssx cccc cccc cccc cccc 1 Luhn(bank+branch) Reversed
Belgium BEkk bbbc cccc ccxx 2 No-pad MOD97
bbbc cccc cc
hearsay, OCM
Bosnia BAkk bbbs sscc cccc ccxx 2 ? official
East Timor TLkk bbbc cccc cccc cccc cxx 2 ISO7064-MOD97-10 official + 2nd
Estonia EEkk bbss cccc cccc cccx 1 ? official doesn't work. Alternate supplied below.
Faroe Islands FOkk bbbb cccc cccc cx 1 ? Banks not responding to emails.
Finland FIkk bbbb bbcc cccc cx 1 ? validate-only code, finnish-hearsay, finnish-other, OCM
France FRkk bbbb bggg ggcc cccc cccc cxx 2 Two systems:
RIB=MOD97
(EBCDIC+pad+concat)
SIREN=sum/10=0
hearsay, OCM
Hungary HUkk bbbs sssk cccc cccc cccc cccx 1 ? ?
Italy ITkk xaaa aabb bbbc cccc cccc ccc [A-Z]{1} Custom pdf pp82-84 OCM
(not this)
Details supplied below.
Luxembourg LUkk cccc cccc cccc xx 2 ? OCM
Macedonia MKkk bbbc cccc cccc cxx 2 ISO7064-MOD97-10 Reversed
Mauritania MRkk bbbb bsss sscc cccc cccc cxx 2 ?
Monaco MCkk bbbb bsss sscc cccc cccc cxx 2 Same as France. @gaetan-be
Montenegro MEkk bbbc cccc cccc cccc xx 2 ISO7064-MOD97-10 Reversed
Netherlands NLkk bbbb cccc cccc cc 0 MOD11(account) Reversed.
hearsay, OCM. Exception:INGB
Norway NOkk bbbb cccc ccx 1 Custom MOD11 OCM
Poland PLkk bbbs sssx cccc cccc cccc cccc 1 ? ?
Portugal PTkk bbbb ssss cccc cccc cccx x 2 ISO7064-MOD97-10 hearsay, OCM
San Marino SMkk xaaa aabb bbbc cccc cccc ccc [A-Z]{1} ?
Serbia RSkk bbbc cccc cccc cccc xx 2 ISO7064-MOD97-10 official, Wikipedia
Slovenia SIkk bbss sccc cccc cxx 2 ISO7064-MOD97-10 Reversed
Spain ESkk bbbb gggg xxcc cccc cccc 2 MOD11 OCM, Wikipedia
Sweden SEkk bbb c cccc cccc cccc ccx 1 ? hearsay

Other situations

Code Country Situation
AT Austria Many, many bank-specific checksum schemes. (hearsay)
DE Germany Many, many bank-specific checksum schemes. (source)
CH Switzerland Some evidence of bank-specific legacy checksum schemes. (hearsay)

@globalcitizen
Copy link
Owner Author

@dem3trio @gaetan-be I've cleaned up this issue and did a fair bit of work yesterday. Still looking for help with remnants.

@globalcitizen globalcitizen changed the title Country-specific sub-BBAN checksums Country-specific checksums Feb 19, 2016
@gaetan-be
Copy link

Monaco is the same system as France

Example IBAN: MC1112739000700011111000h79
RIB = 12739000700011111000h
Checksum = 79

Checked against
http://marlot.org/util/calcul-de-la-cle-rib.php

BTW, did you debug the BE BBAN issue you had? I saw there was 1 digit missing in the BBAN, hence your wrong checksum calculation.

@globalcitizen
Copy link
Owner Author

Thanks for the tip on Monaco, seems to work, released as v2.4.8.

[BE (IANA:.be, ISO3166-1 alpha-2:BE): Belgium]
Is a SEPA member? Yes.
Example IBAN: BE68 5390 0754 7034
 - country  BE
 - checksum 68
 - bban     539007547034
 - bank     539
 - branch
 - account  007547034
 - natcksum 34
    (National checksum manually validated.)
    (National checksum automatically validated.)
    (Correction of national checksum functionality validated.)

Looks fine to me, that's the BE output from utils/test.php

@globalcitizen
Copy link
Owner Author

I've emailed the Danish National Bank about the Faroe Islands system (and to confirm that Denmark had no such pre-IBAN nation-wide domestic checksum scheme) and hope they will respond this week.

We should probably email the others also.

@globalcitizen
Copy link
Owner Author

Their reply: "My recommendation to you will be to ask the Danish Bankers Association ('Finansraadet' in Danish) cf. this link http://www.finansraadet.dk/en/Pages/mainpage.aspx or alternatively one of the Faroese bank directly e.g. Eik Banki, www.eik.fo or Nordoya Sparikassi P/F, www.ns.fo."

I have emailed all of them, as well as this other one. A Finnish bank appears to have a branch there, but I figured they probably haven't been around as long as the others so weren't worth asking.

Also wrote to the Bank of Greenland to verify whether any historic national checksum scheme existed.

@globalcitizen
Copy link
Owner Author

The Netherlands (NL) bank INGB IBANs in the test set I gathered were all failing national checksums, yet are real world IBANs. It seems INGB has been leading the migration away from the previous national checksum scheme. In v2.4.15 a check has been added which returns '' (unimplemented/no known national checksum scheme) when input is determined to derive from the INGB bank. This marks our first bank-specific checksum feature.

@globalcitizen
Copy link
Owner Author

Bank of Slovenia is bank 01 in Slovenia (SI) and has a similar national checksum special case exception. Released in v2.4.17.

@globalcitizen
Copy link
Owner Author

Phew, OK I've searched out a good number of real world example IBANs for all of these countries and committed them under utils/example-ibans/. Based upon testing against those, I've removed a lot of false assumptions about national systems and released a well tested version, v2.5.0.

@globalcitizen
Copy link
Owner Author

Multiple banks of FO did not respond. I think I am going to leave this as 'help wanted' and stop putting effort in, unless people start contributing I'm not sure how much further I can be motivated to go.

@vellotis
Copy link

vellotis commented Jan 29, 2017

I just came over this issue while searching how to calculate Estonian BBAN national check digit. I found a better link that explains the algorithm correctly: http://www.pangaliit.ee/en/settlements-and-standards/example-of-the-use-of-method-7-3-1 (the example PHP code is still invalid)

As an example I implemented it in JavaScript to verify:

var validIban = "EE731010220027689012";
var validBban = validIban.substring(4);
// National Check Digit is calculated on the account number only "EE7310[1022002768901]2"
var accountNumber = validBban.substring(2, validBban.length - 1);
var checkDigit = "101022002768901"
// Convert it to array of numbers
.split("").map(Number)
// 7-3-1 are mapped and multiplied from right-to-left
.reverse().map((val, index) => ([7,3,1][index % 3] * val))
// the results are summed
.reduce((val, previous) => { return val + previous; }, 0)
// the result is subtrackted from the next nearest multiple of 10
% 10 * -1 + 10; // == 2

Sorry for not having interest for further contribution.

@globalcitizen
Copy link
Owner Author

@vellotis Thanks for taking the time to contribute. The information may be utilized in a future update.

@dmccullam
Copy link

UK standards are here: https://www.vocalink.com/customer-support/modulus-checking/

Short summary is that schemes vary by bank (and sometimes branches within each bank), and are not mandatory

@daniel-whitfield-spotcap
Copy link

daniel-whitfield-spotcap commented May 4, 2017

I was going to comment on Estonia, same thing as @vellotis. NVM about Italy.
This issue actually helps me a lot, using node for my implementation.

@xMase
Copy link

xMase commented Aug 20, 2017

this is an italian program documentation that explain how CIN and CHECK DIGIT works:
http://www.artico.name/soft/iban/wiban.htm#cin
this is a javascript based tool for check and verify italian iban:
http://www.m8k.org/tracciatocbinet/iban.php?dahome=s

@globalcitizen
Copy link
Owner Author

@xMase Thanks a lot! I will try to get around to translating and integrating this soon.

@xMase
Copy link

xMase commented Aug 20, 2017

@globalcitizen If you need help do not hesitate to contact me

@rlecour
Copy link

rlecour commented Mar 12, 2018

Your summary indicates Albanian bank codes having Luhn-10 checksum, but based on the following website (which lists "20311003", "20311027", "20311010", etc. as BICs), I'm not sure the assumption is always valid:
https://www.uba.com.al/index.php?option=com_content&view=article&id=65&lang=en&Itemid=612

@globalcitizen
Copy link
Owner Author

@rlecour According to previous research the final digit of those bank and branch identification codes (in my opinion it's not a good idea to call them BICs as that is a specific term used in the SWIFT network) is the Luhn check. As such, there is nothing unexpected here. However, thanks for contributing another English language source.

@francescozanoni
Copy link
Contributor

francescozanoni commented Aug 7, 2018

I've just created a quick-and-dirty translation of Italian BBAN checksum computation here: https://gist.github.com/francescozanoni/6489e64d22e54acaa55dd09773ca458d.
The original was in Visual Basic (properly referenced).

@globalcitizen
Copy link
Owner Author

globalcitizen commented Aug 7, 2018

@francescozanoni Thanks. I am quite busy today but if you like you could try forking the repository, adding a new function to php-iban.php and refactoring the code you just provided to the standard function-based interface we use in php-iban, then submitting a pull request. The function should look something like ...

# Implement the national checksum for an Italian (IT) IBAN
function _iban_nationalchecksum_implementation_it($iban,$mode) {
 # first, extract the BBAN
 $bban = iban_get_bban_part($iban);
 # actual implementation
 #(here you should calculate $expected_nationalchecksum from the code you provided)
 # return result
 if($mode=='find') {
  return $expected_nationalchecksum;
 }
 elseif($mode=='set') {
  return _iban_nationalchecksum_set($iban,$expected_nationalchecksum);
 }
 elseif($mode=='verify') {
  return (iban_get_nationalchecksum_part($iban) == $expected_nationalchecksum);
 }
}

@globalcitizen
Copy link
Owner Author

v2.6.8 released - added national checksum implementation for Italy (IT) thanks to @francescozanoni

@francescozanoni
Copy link
Contributor

francescozanoni commented Aug 14, 2018

Hi, man.
According to http://www.cnb.cz/cs/platebni_styk/iban/download/TR201.pdf at page 96 and to https://www.abbl.lu/topic/iban-and-bic-codes/, Luxembourg has no national checksum within BBAN.

@amichair
Copy link

amichair commented Dec 3, 2020

Thanks for organizing all this info in one place, it's quite helpful!

I just came across an official reference for Albania: https://www.bankofalbania.org/rc/doc/Regulation_no_42_On_the_Structure_and_the_Use_of_the_International_Bank_Account_Number_IBAN_3422_2_6127.pdf (see Annex 4 footnote 1):

Algorithm for module 10: S8 = 10 – (S1 * 9 + S2 * 7 + S3 * 3 + S4 * 1 + S5 * 9 + S6 * 7 + S7 * 3) MOD10
where S is the digit value of n-te n of BIC.

Tried it on one example I have, and it works.

@globalcitizen
Copy link
Owner Author

@amichair Awesome, thanks! Feel free to submit a patch. Try it out with the test scripts and add any extra Albanian example IBANs you can see.

@amichair
Copy link

amichair commented Dec 3, 2020

And if I understand this correctly, Bosnia uses the standard ISO7064-MOD97-1
https://www.cbbh.ba/Content/Read/610?title=The-Instruction-on-the-structure-and-use-of-International-Number-of-the-Bank-Account-(IBAN)---Published-in-the-Official-Gazette-of-Republika-Srpska

I'm currently not working on perl and don't have much spare time to set it up... but at least the reference is here for the next time someone needs it :-) I find most of the effort is in hunting down the specs, whereas implementations are pretty simple.

@amichair
Copy link

amichair commented Dec 3, 2020

Reversed Estonia algorithm from this official-looking js calculator and this code from their IBAN calculator page, both of which have pretty horrible code style :-)

The calculation seems to exclude the 2-digit bank identifier, i.e. it starts at offset 6 of the IBAN. Each digit is multiplied by a respective factor in the sequence 7,1,3,7,1,3,7,1,3...., the products summed up, and modulo 10 applied to the sum. The check digit is the complement to 10 (i.e. 10 - modulus, except if modulus is 0 in which case the check digit is 0). Note that the original code iterates over the digits from end to start, presumably in order to support a variable number of leading zeros, however in the IBAN it's always a fixed size calculation so you can do it in natural order as well.

Tried on 3 IBANs I found in different places, all pass.

@amichair
Copy link

amichair commented Dec 3, 2020

Also, https://www.ecbs.org/Download/Tr201v3.9.pdf
(official document containing various national check digits schemes).

@amichair
Copy link

amichair commented Dec 6, 2020

Mauritania appears to use a variant of ISO7064-MOD97-10 where the result is subtracted from 97 instead of 98 (i.e. the validated checksum is 0 rather than 1). Tested on the registry's example plus two googled real IBANs.

btw once updated perhaps some version of the table above should be added to the IBAN wikipedia page, if they'd accept it...

@amichair
Copy link

amichair commented Dec 6, 2020

The only reference to Poland I found is here, had to search for it in Polish (which I do not speak). Works on 3 examples I found. Uses the weights 3, 9, 7, 1, 3, 9, 7 and modulo 10.

@amichair
Copy link

amichair commented Dec 6, 2020

San Marino is the same as Italy (https://www.ecbs.org/Download/Tr201v3.9.pdf).

@globalcitizen
Copy link
Owner Author

globalcitizen commented Dec 6, 2020

Awesome detective work @amichair! Unfortunately personally I am extremely busy (never this busy in my life) and unable to allocate enough time right now but will get around to it eventually if nobody else contributes.

PS. Examples over here - https://github.com/globalcitizen/php-iban/tree/master/utils/example-ibans

@amichair
Copy link

amichair commented Dec 7, 2020

Last one to wrap it up (I hope) - Finland uses Luhn's. Taken from the Validate_FI code linked above, but without all the account number manipulations that are not needed since in the IBAN it's already expanded to 14 digits, so all that's left is to run Luhn's.

My code (based on my previous comments above) now supports all of the countries in the table above, and all of your example ibans (thanks for the link!) pass validation after removing the various junk punctuation characters.

Yay!

@globalcitizen
Copy link
Owner Author

Thanks @amichair - far and away best research contribution ever :)

@amichair
Copy link

amichair commented Dec 9, 2020

Summed up all of the research and algorithms here:

https://en.wikipedia.org/wiki/International_Bank_Account_Number#National_Check_Digits

@djereg
Copy link

djereg commented Oct 29, 2021

In Hungary: https://farkasdezso.hu/bankszamlaszam/

@Vulwsztyn
Copy link

For what I deduced Bosnian national checksum exists only so that "global"/standard checksum will always be 39.

@Vulwsztyn
Copy link

The links for East timor work no longer

@globalcitizen
Copy link
Owner Author

globalcitizen commented Jun 21, 2022

@Vulwsztyn Bosnia isn't the only one with that property. It's been awhile since I looked at it but IIRC you get that behavior when the national checksum locks the IBAN checksum at a fixed value. For East Timor try http://web.archive.org/ .. feel free to submit a pull request.

@Olympic1
Copy link
Contributor

Olympic1 commented Aug 13, 2022

Leaving a comment here to help myself remember which countries, that I looked into, use a national checksum and which method they use. If a country is already added to php-iban but not in this list, is because I didn't looked into it yet.

Country IBAN format Digits Algorithm References
Albania ALkk bbbs sssx cccc cccc cccc cccc 1 Weighted Official, Official (2nd)
Angola AOkk bbbb ssss cccc cccc cccx x 2 MOD 97-10 EduBanca
Bosnia BAkk bbbs sscc cccc ccxx 2 MOD 97-10 Official
Belgium BEkk bbbc cccc ccxx 2 MOD 97 OCM, Wisfaq
Burkina Faso BFkk bbbb bsss sscc cccc cccc ccxx 2 MOD 97 Combination of Algeria and France
Burundi BIkk bbbb bsss sscc cccc cccc cxx 2 MOD 97 Uses the same as France
Benin BJkk bbbb bsss sscc cccc cccc ccxx 2 MOD 97 Combination of Algeria and France
Central African Republic CFkk bbbb bsss sscc cccc cccc cxx 2 MOD 97 Uses the same as France
Congo CGkk bbbb bsss sscc cccc cccc cxx 2 MOD 97 Uses the same as France
Ivory Coast CIkk bbbb bsss sscc cccc cccc ccxx 2 MOD 97 Combination of Algeria and France
Cameroon CMkk bbbb bsss sscc cccc cccc cxx 2 MOD 97 Uses the same as France
Cape Verde CVkk bbbb ssss cccc cccc cccx x 2 MOD 97-10
Czech Republic CZkk bbbb cccc cxcc cccc cccx 2x1 Weighted Official calculator
Djibouti DJkk bbbb bsss sscc cccc cccc cxx 2 MOD 97 Uses the same as France
Algeria DZkk bbbb bsss sscc cccc cccc xx 2 MOD 97 Official
Estonia EEkk bbss cccc cccc cccx 1 Weighted Official, Official calculator, Official converter (PHP), ECBS
Spain ESkk bbbb ssss xxcc cccc cccc 2 Weighted ECBS, OCM
Finland FIkk bbbb bbcc cccc cx 1 Luhn ECBS, OCM
France FRkk bbbb bsss sscc cccc cccc cxx 2 MOD 97 OCM, ECBS
Gabon GAkk bbbb bsss sscc cccc cccc cxx 2 MOD 97 Uses the same as France
Equatorial Guinea GQkk bbbb bsss sscc cccc cccc cxx 2 MOD 97 Uses the same as France
Croatia HRkk bbbb bbxc cccc cccc x 2x1 MOD 11-10 ECBS
Hungary HUkk bbbb bbbx cccc cccc cccc cccx 2x1 Weighted ECBS
Iceland ISkk bbss ttcc cccc cccc cccc xc 1 Weighted OCM, ECBS
Mali MLkk bbbb bsss sscc cccc cccc ccxx 2 MOD 97 Combination of Algeria and France
Niger NEkk bbbb bsss sscc cccc cccc ccxx 2 MOD 97 Combination of Algeria and France
Senegal SNkk bbbb bsss sscc cccc cccc ccxx 2 MOD 97 Combination of Algeria and France
Chad TDkk bbbb bsss sscc cccc cccc cxx 2 MOD 97 Uses the same as France
Togo TGkk bbbb bsss sscc cccc cccc ccxx 2 MOD 97 Combination of Algeria and France

The following countries don't provide any national checksum

Country IBAN format References
Andorra ADkk bbbb ssss cccc cccc cccc Official
United Arab Emirates AEkk bbbc cccc cccc cccc ccc Official
Azerbaijan AZkk bbbb cccc cccc cccc cccc cccc Official
Bulgaria BGkk bbbb ssss ttcc cccc cc ECBS
Bahrain BHkk bbbb cccc cccc cccc cc Official
Brazil BRkk bbbb bbbb ssss sccc cccc ccct n Official
Belarus BYkk bbbb aaaa cccc cccc cccc cccc Could not access site
Costa Rica CRkk 0bbb cccc cccc cccc cc Official
Cyprus CYkk bbbs ssss cccc cccc cccc cccc
Dominican Republic DOkk bbbb cccc cccc cccc cccc cccc
Egypt EGkk bbbb ssss cccc cccc cccc cccc c EG Bank
Georgia GEkk bbcc cccc cccc cccc cc Official, Official validator
Guatemala GTkk bbbb mmtt cccc cccc cccc cccc Official
Israel ISkk bbbs sscc cccc cccc ccc
Iraq IQkk bbbb sssc cccc cccc ccc
Iran IRkk 0bbt cccc cccc cccc cccc cc

Other situations

Country IBAN format References
Austria ATkk bbbb bccc cccc cccc Multiple checksum calculations. (ECBS)
Switzerland CHkk bbbb bccc cccc cccc c Multiple checksum calculations. (ECBS)
Germany DEkk bbbb bbbb cccc cccc cc Multiple checksum calculations. (Official, ECBS)
Denmark DKkk bbbb cccc cccc cx Has a checksum and found some methods,
but doesn't work for all IBANs I gathered. (MyPlace)
Faroe Islands FOkk bbbb cccc cccc cx Uses the same a Denmark
United Kingdom GBkk bbbb ssss sscc cccc cc Multiple checksum calculations (VocaLink)
Gibraltar GIkk bbbb cccc cccc cccc ccc Multiple checksum calculations (ECBS)
Greenland GLkk bbbb cccc cccc cx Uses the same a Denmark
Greece GRkk bbbs sssc cccc cccc cccc ccc Multiple checksum calculations. (ECBS)
Ireland IEkk bbbb ssss sscc cccc cc Multiple checksum calculations

@amichair
Copy link

Just a reminder, after looking up and verifying everything I could find from here and elsewhere (a few days of research), all the results were updated in the wikipedia page linked above... it would be great if anyone having updates (backed by as authoritative references as possible) could also update the wikipedia tables for the benefit of the world at large :-)

Thanks!

@Olympic1
Copy link
Contributor

Olympic1 commented Aug 15, 2022

I found the checksum for Croatia, or should I say both of them. Croatia uses 2 checksums. The first one uses MOD11-10 for the bank code (seven digits) and the second one also uses MOD11-10 for the account number (ten digits).

I already wrote the algorithm for the checksums, but I want your advice on how I should return them.

  • The verify mode will be easy to implement. If both of them are the same, return true; otherwise false.
  • The find mode should also be easy to implement. I just need to know how you want it to be returned?
    • Both values separately
    • As one string (ex: Bank: x - Account: x)
    • As an array
  • The set mode is easy to implement. Will probably need to write a new function to replace both values.

I would like your input on how to return the results to the user.

@globalcitizen
Copy link
Owner Author

globalcitizen commented Aug 15, 2022

Great work!

Realistically this is an outlier and the number of people who will use both algorithms independently is minimal.

I propose returning the account number checksum only from the existing find method.

However, implementing both algorithms in verify and set would be great.

Documentation will need to be updated to explain this behaviour.

With these reasonable defaults and documentation, I think the edge-case of people having an IBAN passing one national checksum algorithm and failing the other for Croatia can be ignored in the general implementation as unlikely.

@Olympic1
Copy link
Contributor

Olympic1 commented Sep 12, 2022

Found another special case: Estonia.

Estonia has a checksum that is calculated via a weighted MOD 10 using the BBAN (4-14 digits). Another check it uses is that the BBAN has to begin with the bank code and has a specific length per bank code.

Following the steps from the converter (see references):

  • Check if the bban is valid
    • Check that the bban is between 4 and 14 digits
    • Check that the bank code exists and that the bban has the correct length (differs per bank)
    • Check that the bban has the correct national checksum (weights: 7, 3, 1)
  • Check that the bank code in the bban exists
  • Pad the bban to 14 digits
  • Calculate the iban checksum
    • Create iban
      • Add country code (EE)
      • Add checksum (00)
      • Add bank code (ex. 22)
      • Add bban (ex. 00221001121961)
    • Calculate checksum

Examples of the structure for the IBANs and BBANs

Country Checksum Bank code Pad BBAN
EE 75 22 00 221001121961
EE 48 17 000 17000107462
EE 19 10 10220028966019
EE 65 42 0 4207004188303

Using the BBANs from above

Bank code Pad Account number Checksum
22 100112196 1
17 000 10746 2
10 22002896601 9
42 0 700418830 3

The bank code at the beginning of the BBAN is placed in front of the BBAN when creating the IBAN.


References:


@globalcitizen What should I implement in the algorithm? Just the validation of the checksum or also the validation of the bank code and bban?

Another related question: Some countries use a hardcoded iban checksum (most African countries), do I need to modify the implementations to also check for these to prevent malformed IBANs?

@amichair
Copy link

@Olympic1 Can you clarify how this differs from the Estonia entries on the wikipedia page?

@Olympic1
Copy link
Contributor

@Olympic1 Can you clarify how this differs from the Estonia entries on the wikipedia page?

It doesn't have any differences, I found the same references as on the wiki. I'm just asking what I should implement for the validation function.

@globalcitizen
Copy link
Owner Author

Thanks for your continued efforts.

@globalcitizen What should I implement in the algorithm? Just the validation of the checksum or also the validation of the bank code and bban?

Bank codes are always changing and really need to be considered out of scope for this project. It would be great if we could one day add them as a separate database but realistically it's not going to happen because the data is sold and never really up to date even from the 'official' sources, I believe.

That said, the national checksum implementations are pretty edge-case anyway. I think most users of this library do not use them. However, they really are useful in some cases and I believe we are the best source for them right now. In answer to your question:

  • As far as a national implementation goes, the algorithm is definitely the most important.
  • In addition to that, if you can find an authoritative source suggesting strongly that it won't generate false results and do the leg-work, I'm not opposed to a regex-based validation using known account number length information per bank code, eg. ^(?:bank1|bank2|bank3)$ where bank1 might be BANK1CODEHERE[0-9]{12} or similar and this allows both the code and a corresponding length to be checked.

Another related question: Some countries use a hardcoded iban checksum (most African countries), do I need to modify the implementations to also check for these to prevent malformed IBANs?

In my experience these are not hard-coded, rather the existing pre-IBAN national checksum system provides a stable basis for the IBAN checksum algorithm, thus it winds up always being the same value. There is no adequate reason to corrupt the "IBAN checksum should always be validated" (existing/good/cautious) behaviour for the sole sake of saving a few CPU cycles on these cases, and I can't see any other benefit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests