Skip to main content

ms_codec/
consts.rs

1//! v0.1 wire-format constants.
2//!
3//! **Naming convention:** ASCII byte literals (`b'0'`, `b's'`) are used for
4//! values whose semantic meaning is the *character* on the wire (threshold
5//! digit, share-index letter); hex literals (`0x00`) are used for values
6//! whose semantic meaning is the *byte* on the wire (the reserved-prefix
7//! byte). Both produce `u8`; the form chosen reflects which mental model
8//! is more natural at the use site.
9
10/// HRP for ms1 strings (BIP-93 codex32 HRP).
11pub const HRP: &str = "ms";
12
13/// BIP-93 separator character.
14pub const SEPARATOR: char = '1';
15
16/// v0.1 reserved-prefix byte (becomes the v0.2 type discriminator).
17pub const RESERVED_PREFIX: u8 = 0x00;
18
19/// v0.1 emit-side threshold value (ASCII).
20pub const THRESHOLD_V01: u8 = b'0';
21
22/// v0.1 emit-side share-index value (ASCII; "s" denotes the unshared secret per BIP-93).
23pub const SHARE_INDEX_V01: u8 = b's';
24
25/// Short codex32 checksum length in characters.
26pub const CHECKSUM_LEN_SHORT: usize = 13;
27
28/// Allowed v0.1 entr entropy byte lengths (bijective with BIP-39 word counts {12,15,18,21,24}).
29pub const VALID_ENTR_LENGTHS: &[usize] = &[16, 20, 24, 28, 32];
30
31/// Allowed v0.1 total ms1 string lengths (HRP+sep+threshold+id+share+payload+cksum).
32/// Computed: 9 fixed + ceil((entropy_bytes + 1) * 8 / 5) payload symbols + 13 cksum.
33pub const VALID_STR_LENGTHS: &[usize] = &[50, 56, 62, 69, 75];
34
35/// 4-byte type tag — v0.1 emit (also accept).
36pub const TAG_ENTR: [u8; 4] = *b"entr";
37
38/// 4-byte type tags reserved-not-emitted in v0.1 (decoder rejects).
39pub const RESERVED_NOT_EMITTED_V01: &[[u8; 4]] = &[*b"seed", *b"xprv", *b"mnem", *b"prvk"];
40
41#[cfg(test)]
42mod tests {
43    use super::*;
44
45    /// Locks the bijection between VALID_ENTR_LENGTHS and VALID_STR_LENGTHS so
46    /// that a future edit to one without the other fails CI loudly.
47    /// Formula per SPEC §2.4: total = 9 fixed (HRP+sep+threshold+id+share) +
48    /// ceil((entropy_bytes + 1) * 8 / 5) payload symbols + 13 short checksum.
49    #[test]
50    fn valid_str_lengths_match_entr_lengths_via_bijection() {
51        assert_eq!(VALID_ENTR_LENGTHS.len(), VALID_STR_LENGTHS.len());
52        for (i, &entropy_bytes) in VALID_ENTR_LENGTHS.iter().enumerate() {
53            let data_bits = (entropy_bytes + 1) * 8; // +1 for the 0x00 prefix byte
54            let payload_symbols = data_bits.div_ceil(5);
55            let total = 9 + payload_symbols + CHECKSUM_LEN_SHORT;
56            assert_eq!(
57                total, VALID_STR_LENGTHS[i],
58                "entropy {} B -> expected str.len {}, got {} (bijection drift)",
59                entropy_bytes, VALID_STR_LENGTHS[i], total
60            );
61        }
62    }
63}