-
Notifications
You must be signed in to change notification settings - Fork 110
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
Comments
Fun, fun, funZero or more checksum digits Types of algorithms 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:
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:
There are also three other major algorithms:
Summary of Algorithms
Automation 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:
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 systemsData 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.
Other situations
|
@dem3trio @gaetan-be I've cleaned up this issue and did a fair bit of work yesterday. Still looking for help with remnants. |
Monaco is the same system as France Example IBAN: MC1112739000700011111000h79 Checked against 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. |
Thanks for the tip on Monaco, seems to work, released as v2.4.8.
Looks fine to me, that's the BE output from |
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. |
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. |
The Netherlands (NL) bank |
Bank of Slovenia is bank |
Phew, OK I've searched out a good number of real world example IBANs for all of these countries and committed them under |
Multiple banks of |
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. |
@vellotis Thanks for taking the time to contribute. The information may be utilized in a future update. |
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 |
I was going to comment on Estonia, same thing as @vellotis. NVM about Italy. |
this is an italian program documentation that explain how CIN and CHECK DIGIT works: |
@xMase Thanks a lot! I will try to get around to translating and integrating this soon. |
@globalcitizen If you need help do not hesitate to contact me |
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: |
@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. |
I've just created a quick-and-dirty translation of Italian BBAN checksum computation here: https://gist.github.com/francescozanoni/6489e64d22e54acaa55dd09773ca458d. |
@francescozanoni Thanks. I am quite busy today but if you like you could try forking the repository, adding a new function to
|
v2.6.8 released - added national checksum implementation for Italy ( |
Hi, man. |
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):
Tried it on one example I have, and it works. |
@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. |
And if I understand this correctly, Bosnia uses the standard ISO7064-MOD97-1 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. |
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. |
Also, https://www.ecbs.org/Download/Tr201v3.9.pdf |
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... |
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. |
San Marino is the same as Italy (https://www.ecbs.org/Download/Tr201v3.9.pdf). |
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 |
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! |
Thanks @amichair - far and away best research contribution ever :) |
Summed up all of the research and algorithms here: https://en.wikipedia.org/wiki/International_Bank_Account_Number#National_Check_Digits |
In Hungary: https://farkasdezso.hu/bankszamlaszam/ |
For what I deduced Bosnian national checksum exists only so that "global"/standard checksum will always be 39. |
The links for East timor work no longer |
@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. |
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
The following countries don't provide any national checksum
Other situations
|
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! |
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.
I would like your input on how to return the results to the user. |
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 However, implementing both algorithms in 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. |
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):
Examples of the structure for the IBANs and BBANs
Using the BBANs from above
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? |
@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. |
Thanks for your continued efforts.
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:
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. |
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.
The text was updated successfully, but these errors were encountered: