OpenPay (1 crate, 1801 LOC, 57 tests)
op-bin BIN/IIN database + range matching + card-network
classification. 8-digit normalized prefix Bin +
BinRange. Sorted-vec interval tree with O(log N) point
lookup + overlap rejection. CardNetwork classify()
with structural rules (Visa 4, MC 51-55/2221-2720,
Amex 34/37, Discover, JCB, Diners, UnionPay, RuPay,
Mir, Troy, Maestro, Elo). Static prefix tables +
build_default_tree(). ISO/IEC 7812-1 Annex B Luhn
(validate / is_valid / check_digit). Card-type +
issuer-country + Durbin regulated-debit. PCI-safe:
8-digit cap, no full-PAN APIs.
Smart Byte (1 crate, ~1500 LOC, 20 tests)
smart-byte-tendermint BFT consensus. Step enum + Round + propose/prevote/
precommit/commit FSM with voting-power tallies.
ValidatorSet with 2/3+1 quorum, 1/3+1 trust
threshold, round-robin proposer. Block / Header /
Commit / CommitSig with Blake3 hashing. Light client
(sequential + skipping). ABCI Application trait +
EchoApp. DuplicateVoteEvidence + LightClientAttackEvidence.
IBC ClientState + ConsensusState + light-client
update.
EOC (1 crate, 2084 LOC, 23 tests)
eoc-safety AI safety primitives. RegexSet over 16 prompt-injection
signatures. 13-family jailbreak detector (DAN/DUDE/
Grandma/STAN/AIM/dev-mode/etc.). Presidio-style PII
redactor with Luhn-validated CC. Toxicity / bias /
NSFW classifier traits + heuristic baselines (5-axis
bias, 4-category NSFW with hard-reject for minors).
Constitutional AI critique→revise loop. Composable
InputGuard / OutputGuard pipelines. JSON-Schema-subset
output validator. Token-bucket rate limiter +
abuse-window detection. Red-team replay harness.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
54 lines
1.5 KiB
Rust
54 lines
1.5 KiB
Rust
//! Industry test PANs across the major networks should all pass
|
|
//! the Luhn check; perturbing the last digit should fail.
|
|
|
|
use op_bin::luhn;
|
|
|
|
#[test]
|
|
fn industry_test_pans_pass() {
|
|
// Visa
|
|
assert!(luhn::is_valid("4111111111111111"));
|
|
assert!(luhn::is_valid("4012888888881881"));
|
|
// Mastercard
|
|
assert!(luhn::is_valid("5555555555554444"));
|
|
assert!(luhn::is_valid("5105105105105100"));
|
|
// Amex
|
|
assert!(luhn::is_valid("378282246310005"));
|
|
assert!(luhn::is_valid("371449635398431"));
|
|
// Discover
|
|
assert!(luhn::is_valid("6011111111111117"));
|
|
assert!(luhn::is_valid("6011000990139424"));
|
|
// JCB
|
|
assert!(luhn::is_valid("3530111333300000"));
|
|
}
|
|
|
|
#[test]
|
|
fn perturbed_last_digit_fails() {
|
|
// Flip the check digit of each — should fail.
|
|
assert!(!luhn::is_valid("4111111111111110"));
|
|
assert!(!luhn::is_valid("5555555555554445"));
|
|
assert!(!luhn::is_valid("378282246310006"));
|
|
}
|
|
|
|
#[test]
|
|
fn check_digit_recovers_industry_test_pans() {
|
|
let pairs = [
|
|
("411111111111111", '1'),
|
|
("555555555555444", '4'),
|
|
("37828224631000", '5'),
|
|
("353011133330000", '0'),
|
|
];
|
|
for (partial, expected) in pairs {
|
|
let cd = luhn::check_digit(partial).expect("ok");
|
|
assert_eq!(
|
|
char::from_digit(cd as u32, 10),
|
|
Some(expected),
|
|
"for partial {partial}",
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn non_digit_input_rejected() {
|
|
assert!(!luhn::is_valid("4111-1111-1111-1111"));
|
|
assert!(!luhn::is_valid(" 4111111111111111"));
|
|
}
|