use codex32::Codex32String;
const V1_STRING: &str = "ms10testsxxxxxxxxxxxxxxxxxxxxxxxxxx4nzvca9cmczlw";
const V1_MASTER_SEED_HEX: &str = "318c6318c6318c6318c6318c6318c631";
#[test]
fn vector_1_no_split_16_byte_secret() {
let parsed =
Codex32String::from_string(V1_STRING.to_string()).expect("§93.1 parses");
assert_eq!(
parsed.to_string(),
V1_STRING,
"§93.1 should Display-round-trip case-preservingly"
);
let data = parsed.parts().data();
let expected = hex_to_bytes(V1_MASTER_SEED_HEX);
assert_eq!(
&data[..expected.len()],
&expected[..],
"§93.1 first 16 bytes of payload should equal the BIP master seed"
);
}
const V2_RECOVERED_S_SHARE: &str = "MS12NAMES6XQGUZTTXKEQNJSJZV4JV3NZ5K3KWGSPHUH6EVW";
const V2_MASTER_SEED_HEX: &str = "d1808e096b35b209ca12132b264662a5";
#[test]
fn vector_2_k_of_2_share_s_recovers_secret() {
let parsed = Codex32String::from_string(V2_RECOVERED_S_SHARE.to_string())
.expect("§93.2 recovered S share parses");
assert_eq!(
parsed.to_string(),
V2_RECOVERED_S_SHARE,
"§93.2 should Display-round-trip case-preservingly (uppercase form)"
);
let data = parsed.parts().data();
let expected = hex_to_bytes(V2_MASTER_SEED_HEX);
assert_eq!(
&data[..expected.len()],
&expected[..],
"§93.2 first 16 bytes of S-share payload should equal the BIP master seed"
);
}
const V3_S_SHARE: &str = "ms13cashsllhdmn9m42vcsamx24zrxgs3qqjzqud4m0d6nln";
const V3_MASTER_SEED_HEX: &str = "ffeeddccbbaa99887766554433221100";
#[test]
fn vector_3_k_of_3_share_s_canonical() {
let parsed =
Codex32String::from_string(V3_S_SHARE.to_string()).expect("§93.3 parses");
assert_eq!(parsed.to_string(), V3_S_SHARE, "§93.3 round-trips");
let data = parsed.parts().data();
let expected = hex_to_bytes(V3_MASTER_SEED_HEX);
assert_eq!(
&data[..expected.len()],
&expected[..],
"§93.3 first 16 bytes of S-share payload should equal the BIP master seed"
);
}
const V4_STRING: &str =
"ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqqtum9pgv99ycma";
const V4_MASTER_SEED_HEX: &str =
"ffeeddccbbaa99887766554433221100ffeeddccbbaa99887766554433221100";
#[test]
fn vector_4_no_split_32_byte_secret() {
let parsed =
Codex32String::from_string(V4_STRING.to_string()).expect("§93.4 parses");
assert_eq!(parsed.to_string(), V4_STRING, "§93.4 round-trips");
let data = parsed.parts().data();
let expected = hex_to_bytes(V4_MASTER_SEED_HEX);
assert_eq!(
&data[..expected.len()],
&expected[..],
"§93.4 first 32 bytes of payload should equal the BIP master seed"
);
}
const V5_STRING: &str =
"MS100C8VSM32ZXFGUHPCHTLUPZRY9X8GF2TVDW0S3JN54KHCE6MUA7LQPZYGSFJD6AN074RXVCEMLH8WU3TK925ACDEFGHJKLMNPQRSTUVWXY06FHPV80UNDVARHRAK";
const V5_MASTER_SEED_HEX: &str =
"dc5423251cb87175ff8110c8531d0952d8d73e1194e95b5f19d6f9df7c01111104c9baecdfea8cccc677fb9ddc8aec5553b86e528bcadfdcc201c17c638c47e9";
#[test]
fn vector_5_long_codex32_512_bit_secret() {
let parsed =
Codex32String::from_string(V5_STRING.to_string()).expect("§93.5 parses");
assert_eq!(
parsed.to_string(),
V5_STRING,
"§93.5 (all-uppercase) round-trips"
);
let data = parsed.parts().data();
let expected = hex_to_bytes(V5_MASTER_SEED_HEX);
assert_eq!(
&data[..expected.len()],
&expected[..],
"§93.5 first 64 bytes of payload should equal the BIP master seed"
);
}
const INVALID_VECTORS: &[&str] = &[
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxve740yyge2ghq",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxve740yyge2ghp",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxlk3yepcstwr",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxx6pgnv7jnpcsp",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxx0cpvr7n4geq",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxm5252y7d3lr",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxrd9sukzl05ej",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxc55srw5jrm0",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxgc7rwhtudwc",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxx4gy22afwghvs",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxe8yfm0",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxvm597d",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxme084q0vpht7pe0",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxme084q0vpht7pew",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxqyadsp3nywm8a",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxzvg7ar4hgaejk",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcznau0advgxqe",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxch3jrc6j5040j",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx52gxl6ppv40mcv",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7g4g2nhhle8fk",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx63m45uj8ss4x8",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxy4r708q7kg65x",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxurfvwmdcmymdufv",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxcsyppjkd8lz4hx3",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxu6hwvl5p0l9xf3c",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwqey9rfs6smenxa",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxv70wkzrjr4ntqet",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx3hmlrmpa4zl0v",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxrfggf88znkaup",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxpt7l4aycv9qzj",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxus27z9xtyxyw3",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcwm4re8fs78vn",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxw0a4c70rfefn4",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxk4pavy5n46nea",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxx9lrwar5zwng4w",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxr335l5tv88js3",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxvu7q9nz8p7dj68v",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxpq6k542scdxndq3",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkmfw6jm270mz6ej",
"ms12fauxxxxxxxxxxxxxxxxxxxxxxxxxxzhddxw99w7xws",
"ms12fauxxxxxxxxxxxxxxxxxxxxxxxxxxxx42cux6um92rz",
"ms12fauxxxxxxxxxxxxxxxxxxxxxxxxxxxxxarja5kqukdhy9",
"ms12fauxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxky0ua3ha84qk8",
"ms12fauxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx9eheesxadh2n2n9",
"ms12fauxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx9llwmgesfulcj2z",
"ms12fauxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx02ev7caq6n9fgkf",
"ms10fauxxxxxxxxxxxxxxxxxxxxxxxxxxxx0z26tfn0ulw3p",
"ms1fauxxxxxxxxxxxxxxxxxxxxxxxxxxxxxda3kr3s0s2swg",
"0fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2",
"10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2",
"ms0fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2",
"m10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2",
"s10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2",
"0fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxhkd4f70m8lgws",
"10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxhkd4f70m8lgws",
"m10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxx8t28z74x8hs4l",
"s10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxh9d0fhnvfyx3x",
"Ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2",
"mS10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2",
"MS10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2",
"ms10FAUXsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2",
"ms10fauxSxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2",
"ms10fauxsXXXXXXXXXXXXXXXXXXXXXXXXXXuqxkk05lyf3x2",
"ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxUQXKK05LYF3X2",
];
#[test]
fn invalid_corpus_length_is_64() {
assert_eq!(INVALID_VECTORS.len(), 64);
}
#[test]
fn all_invalid_vectors_rejected_by_codex32() {
let mut failures = Vec::new();
for (i, s) in INVALID_VECTORS.iter().enumerate() {
match Codex32String::from_string(s.to_string()) {
Ok(parsed) => failures.push(format!(
"vector[{i}] should be rejected but parsed successfully: input={s:?} parsed={parsed:?}"
)),
Err(_e) => {
}
}
}
assert!(
failures.is_empty(),
"{} of 64 invalid vectors leaked through `Codex32String::from_string`:\n{}",
failures.len(),
failures.join("\n")
);
}
fn hex_to_bytes(s: &str) -> Vec<u8> {
assert!(s.len() % 2 == 0, "hex must be even-length: {s}");
(0..s.len())
.step_by(2)
.map(|i| {
u8::from_str_radix(&s[i..i + 2], 16).expect("valid hex")
})
.collect()
}