Skip to content

Navigation Menu

Sign in
Sign up

Repository files navigation

ISO 17442 conformance

Reference material and a strict reference implementation for ISO 17442, the international standard for the Legal Entity Identifier (LEI), together with a published corpus of really-published non-conforming values taken from named public registers.

This is not another LEI validator. Validating an LEI is commodity code and several libraries already do it. What is provided here is a conformance model that distinguishes four outcomes instead of two, a test corpus whose every defect is a value some register actually published, and the measured finding that the widely used commodity libraries are built for a different job and will under-report defects if you point them at a register.

What ISO 17442 is

ISO 17442 is published by ISO/TC 68 (Financial services) in three parts. The single-part editions are withdrawn, and citations to them are stale.

Part Title Status
ISO 17442-1:2020 Financial services. Legal entity identifier (LEI). Part 1: Assignment Current. Reviewed and confirmed 2026
ISO 17442-2:2020 Part 2: Application in digital certificates Current
ISO 17442-3:2024 Part 3: Verifiable LEIs (vLEIs) Current. Published October 2024
ISO 17442:2019 Financial services. Legal entity identifier (LEI) Withdrawn. Replaced by Parts 1 and 2
ISO 17442:2012 Financial services. Legal Entity Identifier (LEI) Withdrawn. Revised as the 2019 edition

The structure of the identifier has not changed across these editions. An LEI is 20 characters: 18 drawn from upper case A-Z and 0-9, followed by 2 decimal check digits computed under ISO 7064 MOD 97-10.

The check digit rule

Expand every character to its base-36 value as decimal digits (A becomes 10, Z becomes 35), read the result as one large integer, and take it modulo 97. For a conforming LEI the remainder is 1. Because MOD 97-10 can never yield them, the check digit pair is never 00, 01 or 99, so those three values are impossible rather than merely wrong.

Two consequences follow, and both matter more than they look. An LEI is self-validating: any holder can reject an impossible value with no lookup and no network call. And a truncated LEI is not a slightly damaged LEI, it is an unverifiable string, because truncation discards the very digits that make the identifier self-validating.

Four conformance states, not a boolean

A boolean collapses distinct governance problems that need different responses.

State Meaning What it usually indicates
valid Well formed and the MOD 97-10 remainder is 1 Conforming
fails-check-digits Well formed, arithmetic rejects it A recording error such as a transposition, or a letter O typed for a zero
impossible-check-digits Well formed but ends 00, 01 or 99 A placeholder or filler value, never a damaged real LEI
not-checkable Wrong length, or characters outside the repertoire Usually truncation by a republisher. The defect belongs to the publisher, not to the Global LEI System
from iso17442 import classify, Conformance
classify("506700GE1G29325QX363") # Conformance.VALID
classify("5493O00MN7XN3BBKCE67") # FAILS_CHECK_DIGITS (letter O for zero)
classify("00000000000000000000") # IMPOSSIBLE_CHECK_DIGITS
classify("7H6GLXDRUGQFU57R") # NOT_CHECKABLE (truncated to 16 characters)

Why the commodity libraries under-report

python-stdnum provides stdnum.lei, and it is correct for the job it was designed for. Its documented convention, shared across the whole library, is to compact() the input first, stripping separators and surrounding whitespace and upper-casing, and then validate. validate() returns the canonical form. That is right for input validation, where a human may type an identifier with dashes and you want to accept it.

It is wrong for publication auditing, where the deviation is the finding. Measured behaviour:

stdnum.lei.is_valid('5493000mn7xn3bbkce67') -> True
stdnum.lei.is_valid(' 506700GE1G29325QX363') -> True

ISO 17442 admits only upper case A-Z and 0-9, so neither value is a conforming LEI. Audit a register with a normalising validator and every lower-cased or space-padded value it publishes is silently counted as conforming. This is not hypothetical: lower-case LEI values occur in published US bank register data.

The rule this library follows is therefore: never normalise before assessing. Canonicalise afterwards if you need to, but the assessment must see exactly what was published.

Input validation and publication auditing pull in opposite directions. Almost every available implementation is built for the first. If you are measuring what a register published, check which one you are holding.

The corpus

iso17442/vectors.py carries the test vectors, each with its expected state and its provenance. Every defective value was published by a named register, not invented, because a suite built only from synthetic defects tends to miss the shapes registers actually emit. Truncation is the clearest example: it looks nothing like a typo.

RDF and SHACL

shapes/ carries the same rules for RDF data: SHACL Core shapes for the lexical form, and the full ISO 7064 MOD 97-10 arithmetic as a SHACL-SPARQL constraint, which is the only form that catches a transposition.

fibo/ carries a draft OWL datatype restriction for FIBO's fibo-be-le-lei:LegalEntityIdentifier, offered in response to edmcouncil/fibo#2238. FIBO asserts ISO 17442 conformance in its definition but carries no syntactic constraint, so a FIBO graph cannot currently distinguish a valid LEI from a truncated one. Note the limitation: an xsd:pattern facet catches length, character set and impossible check digits, but no regular expression can express MOD 97-10 arithmetic, so a transposition still passes.

Deriving a CUSIP to LEI crosswalk without a licence

A US ISIN is the country code, then a 9 character national number, then a check digit, and for US securities that national number is the CUSIP. GLEIF publishes an ISIN to LEI mapping under CC0. Slicing characters 3 to 11 of the US rows yields a CUSIP to LEI crosswalk from public-domain inputs alone.

Measured on the GLEIF file of 8 August 2026: 9,119,948 rows, of which 2,281,318 are US, every one with a CUSIP-shaped national number, giving 2,281,318 distinct CUSIP-9 values across 29,651 CUSIP-6 issuer prefixes.

Null result: zero of those 2,281,318 CUSIP-9 values map to more than one issuer LEI. The instrument-level crosswalk is internally consistent.

Caution on the issuer level. 331 CUSIP-6 prefixes (1.12%) carry more than one LEI, and it is tempting to read that as register disagreement. It is not. Every case examined is a fund family: CUSIP-6 identifies the trust, while the LEI identifies the individual fund series, so the one-to-many relationship is correct. The two identifiers sit at different levels of the hierarchy. Anyone migrating from a CUSIP-6 entity key to an LEI should expect this and should not treat it as a data quality defect.

Install and test

pip install -e .
python -m pytest tests/ -q

Licence and citation

Code and shapes are MIT. The conformance states, the corpus provenance and the measurements above may be cited via CITATION.cff.

About

ISO 17442 legal entity identifier conformance: a four-state model, a corpus of really-published defects, SHACL forms and a draft FIBO facet

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

AltStyle によって変換されたページ (->オリジナル) /