MOD11 (Modulus11) er en kontrollsifferalgoritme som blant annet benyttes for å validere kontonumre i norske banker, organisasjonsnummer og det siste sifferet i norske fødselsnummer. (Norske fødselsnummer har to kontrollsifre, det nest siste er også et modulo 11-kontrollsiffer, men ved beregningen av dette benyttes det multiplikatorer i en annen og uregelmessig rekkefølge).

Bakgrunn

rediger

Kontrollsiffer benyttes for å oppdage feil ved inntasting av f.eks. KID, kontonumre og fødselsnumre. Det benyttes i all hovedsak to algoritmer for dette, MOD10 og MOD11. Disse kontrollsifrene kontrolleres maskinelt ved OCR-lesing i skranken hos banker. En del IT-systemer kontrollerer også disse kontrollsifre for å sikre at brukere ikke har tastet feil. Dette inkluderer nettbanker og lønnssystemer.

Dersom to eller flere siffer i det inntastede felt er feil, øker sjansen for at kontrollsifferet beregnes til det samme, og at feilen ikke oppdages. Den vil likevel ikke være mer enn om lag 9 % for MOD11 – og 10 % for MOD10. Dersom en tilfeldig tallrekke kontrolleres, er sannsynligheten om lag 9 % for at siste siffer stemmer med kontrollsiffer beregningen (MOD11 bruker også tegnet «-» som et kontrolltegn, så det blir elleve varianter).

Denne kontrollsifferalgoritmen er også designet til å oppdage ombytting av sifre. Det er noe økt sjanse for at brukere taster inn f.eks. en KID der to sifre har byttet plass. Derfor brukes et prinsipp med varierende vekttall for hvert siffer i algoritmen nedenfor. I modulus-10 kan det oppdages om to påfølgende siffer har byttet plass, men ikke første og siste i gruppe på tre. Modulus11 vil også oppdage det.

Beregning av kontrollsiffer med Modulus11

rediger

Et tenkt kontonummer er 1234.56.78903. Det siste sifferet i kontonummeret er et kontrollsiffer. I dette eksempelet er kontrollsifferet 3. Kontonummeret uten kontrollsiffer (og uten skilletegn) er 1234567890.

Hvert siffer i eksempelet over multipliseres med vekttallene 2,3,4,5,6,7,2,3,4,5 (eventuelt videre ,6,7,2,3 og så videre for tall med flere sifre), regnet fra høyre mot venstre.

0 × 2 = 0

9 × 3 = 27

8 × 4 = 32

7 × 5 = 35

6 × 6 = 36

5 × 7 = 35

4 x 2 = 8

3 x 3 = 9

2 x 4 = 8

1 x 5 = 5

Summen er 0 + 27 + 32 + 35 + 36 + 35 + 8 + 9 + 8 + 5 = 195.

Kontrollsifferet blir nå det tallet som må legges til summen for å få et tall som er delelig med 11.

Summen divideres med 11 og vi noterer «resten» som blir 8 i dette tilfellet. Denne resten trekkes fra 11 og vi får 3 som blir kontrollsifferet.

11 - 8 = kontrollsifferet 3

Komplett og gyldig kontonummer i dette eksempelet er derfor 1234.56.78903.

Dersom summen er delelig med 11 blir også resten 0 og kontrollsifferet 0. Dersom «resten» ved divisjonen blir 1 skal «kontrollsifferet» ha tallverdien 10, da benyttes isteden et minustegn (eller bindestrek) istedenfor kontrollsifferet. Imidlertid gjelder for kontonumre (og også for personnummer) at slike tall isteden skal forkastes slik at for de typene tall kan kontrollsiffer «-» aldri forekomme.

Implementasjoner i forskjellige programmeringspråk

rediger
public static bool ValidateMod11(string bankAccountNumber)
{
    var normalized = Regex.Replace(bankAccountNumber, @"[\s.]+", string.Empty);
    if (normalized.Length != 11)
    {
        return false;
    }

    var weights = new[] { 5, 4, 3, 2, 7, 6, 5, 4, 3, 2 };
    var sum = 0;
    for (var i = 0; i < 10; i++)
    {
        sum += int.Parse(normalized[i].ToString()) * weights[i];
    }

    var remainder = sum % 11;
    var controlDigit = int.Parse(normalized[10].ToString());

    return controlDigit == (remainder == 0 ? 0 : 11 - remainder);
}

JavaScript

rediger
  function validateKontonummerMod11(kontonummer) {
    const weights = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2];
    const kontonummerWithoutSpacesAndPeriods = kontonummer.replace(/[\s.]+/g, '');
    if (kontonummerWithoutSpacesAndPeriods.length !== 11) {
      return false;
    } else {
      const sjekksiffer = parseInt(kontonummerWithoutSpacesAndPeriods.charAt(10), 10);
      const kontonummerUtenSjekksiffer = kontonummerWithoutSpacesAndPeriods.substring(0, 10);
      let sum = 0;
      for (let index = 0; index < 10; index++) {
        sum += parseInt(kontonummerUtenSjekksiffer.charAt(index), 10) * weights[index];
      }
      const remainder = sum % 11;
      return sjekksiffer === (remainder === 0 ? 0 : 11 - remainder);
    }
  }

Python

rediger
  def kid_mod11_wiki(a):
    cross = sum([int(val)*[2,3,4,5,6,7][idx%6] for idx,val in enumerate(list(str(a))[::-1])]) 
    return "%s%s" % (a,cross % 11 == 10 and '-' or 11-(cross % 11))

[1]

public class KontonummerValidator {
    public static boolean gyldigKontonummer(String kontonr) {
        // Fjern whitespace og punktum fra kontonummer (enkelte liker å formatere kontonummer med 1234.56.78903)
        kontonr = StringUtils.remove(kontonr, ' ');
        kontonr = StringUtils.remove(kontonr, '.');

        // Skal inneholde 11 siffer og kun tall
        if (kontonr.length() != 11 || !StringUtils.isNumeric(kontonr)) {
            return false;
        }

        int sisteSiffer = Character.getNumericValue(kontonr.charAt(kontonr.length() - 1));

        return getCheckDigit(kontonr) == sisteSiffer;
    }

    private static int getCheckDigit(String number) {
        int lastIndex = number.length() - 1;
        int sum = 0;

        for (int i = 0; i < lastIndex; i++) {
            sum += Character.getNumericValue(number.charAt(i)) * getWeightNumber(i);
        }

        int remainder = sum % 11;

        return getCheckDigitFromRemainder(remainder);
    }

    private static int getWeightNumber(int i) {
        return 7 - (i + 2) % 6;
    }

    private static int getCheckDigitFromRemainder(int remainder) {
        switch (remainder) {
        case 0:
            return 0;

        default:
            return 11 - remainder;
        }
    }
}

Kotlin

rediger
fun validMod11(cid: String): Boolean {
    val kontrollSiffer = cid[cid.length - 1].toString().toInt()
    val nummerUtenKontrollSiffer = cid.substring(0, cid.length - 1)
    val resultat = nummerUtenKontrollSiffer
        .reversed()
        .mapIndexed { i, v -> v.toString().toInt() * ((i % 6) + 2) }
        .sum()
	return (if (resultat == 0) 0 else 11 - (resultat % 11)) == kontrollSiffer
}
func ValidateMod11(str string) bool {
        if ok, _ := regexp.MatchString("^[0-9]{11}$", str); !ok {
                return false
        }

        var sum int
        for i, w := range []int{5, 4, 3, 2, 7, 6, 5, 4, 3, 2} {
                sum += int(str[i]-'0') * w
        }

        return int(str[10]-'0') == (1100-sum)%11
}

Se også

rediger

Referanser

rediger
Autoritetsdata