Crate cusip

source · []
Expand description


cusip provides a CUSIP type for working with validated Committee on Uniform Security Identification Procedures (CUSIP) identifiers as defined in ANSI X9.6-2020 Financial Services - Committee on Uniform Security Identification Procedures Securities Identification CUSIP (“The Standard”).

CUSIP Global Services (CGS) has a page describing CUSIP identifiers.

A CUSIP “number” (so-called by The Standard because originally they were composed only of decimal digits, but now they can also use letters) is comprised of 9 ASCII characters with the following parts, in order (Section 3.1 “CUSIP number length” of the standard):

  1. A six-character uppercase alphanumeric Issuer Number.
  2. A two-character uppercase alphanumeric Issue Number.
  3. A single decimal digit representing the Check Digit computed using what The Standard calls the “modulus 10 ‘double-add-double’ technique”.

Note: The Standard does not specify uppercase for the alphabetic characters but uniformly presents examples only using uppercase. Therefore this implementation treats uppercase as required for both parsing and validation, while offering a parse_loose() alternative that allows mixed case. There is no “loose” version of validation because of the risk of confusion if it were used to validate a set of strings – the number of distinct string values could differ from the number of distinct CUSIP identifiers because each identifier could have multiple string representations in the set, potentially resulting in data integrity problems.

Although The Standard asserts that CUSIP numbers are not assigned using alphabetic ‘I’ and ‘O’ nor using digits ‘1’ and ‘0’ to avoid confusion, digits ‘1’ and ‘0’ are common in current real-world CUSIP numbers. A survey of a large set of values turned up none using letter ‘I’ or letter ‘O’, so it is plausible that ‘I’ and ‘O’ are indeed not used. In any case, this crate does not treat any of these four character values as invalid.

CUSIP number “issuance and dissemination” are managed by CUSIP Global Services (CGS) per section B.1 “Registration Authority” of The Standard. In addition, there are provisions for privately assigned identifiers (see below).


Use the parse() or parse_loose() functions to convert a string to a validated CUSIP:

match cusip::parse(some_string) {
    Ok(cusip) => { /* ... */ }
    Err(err) => { /* ... */ }

or take advantage of CUSIP’s implementation of the FromStr trait and use the parse() method on the str type:

let cusip: cusip::CUSIP = some_string.parse().unwrap();

If you just want to check if a string value is in a valid CUSIP format (with the correct Check Digit), use validate().

let is_valid_cusip = cusip::validate(some_string);


Since its adoption in 1968, CUSIP has been the standard security identifier for:

  • United States of America
  • Canada
  • Bermuda
  • Cayman Islands
  • British Virgin Islands
  • Jamaica

Since the introduction of the ISIN standard (ISO 6166), CUSIP has been adopted as the ISIN Security Identifier for many more territories in the creation of ISIN identifiers.

Private use

The CUSIP code space has allocations for both private Issuer Numbers and private Issue Numbers.

You can determine whether or not a CUSIP is intended for private use by using the CUSIP::is_private_use() method. A private use CUSIP is one that either has_private_issuer() or is_private_issue(). The has/is distinction is because a CUSIP represents (“is”) an Issue (Security) offered by an “Issuer” (the Security “has” an Issuer).

Private Issue Numbers

In Section 3.2 “Issuer Number” of The Standard, “privately assigned identifiers” are defined as those having Issuer Number ending in “990” through “999”.

In Section C.8.1.3 “Issuer Numbers Reserved for Internal Use” of the Standard, expands that set with the following additional Issuer Numbers:

  • those ending in “99A” through “99Z”
  • those from “990000” through “999999”
  • those from “99000A” through “99999Z”

Such CUSIPs are reserved for this use only, and will not be assigned by the Registration Authority.

You can use the CUSIP::has_private_issuer() method to detect this case.

Note that The Standard says that in all cases a “Z” in the “5th and 6th position has been reserved for use by the Canadian Depository for Securities.” There are no examples given, and it is not clear whether this means literally “and” (“0000ZZ005” would be reserved but “0000Z0002” and “00000Z003” would not) or if it actually means “and/or” (all of “0000ZZ005”, “0000Z0002” and “00000Z003” would be reserved). Because this is not clear from the text of the standard, this rule is not represented in this crate.

Private Issuer Numbers

In Section C.8.2.6 “Issue Numbers Reserved for Internal Use”, The Standard specifies that Issue Numbers “90” through “99” and “9A” through “9Y” are reserved for private use, potentially in combination with non-private-use Issuer Numbers.

CUSIP International Numbering System (CINS)

While the primary motivation for the creation of the CUSIP standard was representation of U.S. and Canadian securities, it was extended in 1989 for non-North American issues through definition of a CUSIP International Numbering System (CINS). On 1991-01-01 CINS became the only allowed way of issuing CUSIP identifiers for non-North American securities.

A CUSIP with a letter in the first position is a CINS number, and that letter identifies the country or geographic region of the Issuer.

Use the CUSIP::is_cins() method to discriminate between CINS and conventional CUSIPs, and the CUSIP::cins_country_code() method to extract the CINS Country Code as an Option<char>.

The country codes are:

AAustriaHSwitzerlandO(Unused)VAfrica - Other
BBelgiumI(Unused)PSouth AmericaWSweden
CCanadaJJapanQAustraliaXEurope - Other
ESpainLLuxembourgSSouth AfricaZ(Unused)
GUnited KingdomNNetherlandsUUnited States

Even though country codes I, O and Z are unused, this crate reports CUSIPs starting with those letters as being in the CINS format via CUSIP::is_cins() and returns them via CUSIP::cins_country_code() because The Standard says CINS numbers are those CUSIPs starting with a letter. If you care about the distinction between the two, use CUSIP::is_cins_base() and CUSIP::is_cins_extended().

See section C.7.2 “Non-North American Issues – CUSIP International Numbering System” of The Standard.

Private Placement Number (PPN)

According to Section C.7.2 “Private Placements” of The Standard, The Standard defines three non-alphanumeric character values to support a special use for the “PPN System”. They are ‘*’ (value 36), ‘@’ (value 37) and ‘#’ (value 38) (see section A.3 “Treatment of Alphabetic Characters”.

CUSIPs using these extended characters are not supported by this crate because the extended characters are not supported by ISINs, and CUSIPs are incorporated as the Security Identifier for ISINs for certain Country Codes.

This crate is part of the Financial Identifiers series:

  • CUSIP: Committee on Uniform Security Identification Procedures (ANSI X9.6-2020)
  • ISIN: International Securities Identification Number (ISO 6166:2021)
  • LEI: Legal Entity Identifier (ISO 17442:2020)


pub use error::CUSIPError;





A CUSIP in confirmed valid format.


Build a CUSIP from its parts: an Issuer Number and an Issue Number. The Check Digit is automatically computed.

Build a CUSIP from a Payload (an already-concatenated Issuer Number and Issue Number). The Check Digit is automatically computed.

Compute the Check Digit for an array of u8. No attempt is made to ensure the input string is in the CUSIP payload format or length. If an illegal character (not an ASCII digit and not an ASCII uppercase letter) is encountered, this function will panic.

Parse a string to a valid CUSIP or an error, requiring the string to already be only uppercase alphanumerics with no leading or trailing whitespace in addition to being the right length and format.

Parse a string to a valid CUSIP or an error message, allowing the string to contain leading or trailing whitespace and/or lowercase letters as long as it is otherwise the right length and format.

Test whether or not the passed string is in valid CUSIP format, without producing a CUSIP struct value.