bech32m.rs
1 // Copyright (c) 2025-2026 ACDC Network 2 // This file is part of the alphaos library. 3 // 4 // Alpha Chain | Delta Chain Protocol 5 // International Monetary Graphite. 6 // 7 // Derived from Aleo (https://aleo.org) and ProvableHQ (https://provable.com). 8 // They built world-class ZK infrastructure. We installed the EASY button. 9 // Their cryptography: elegant. Our modifications: bureaucracy-compatible. 10 // Original brilliance: theirs. Robert's Rules: ours. Bugs: definitely ours. 11 // 12 // Original Aleo/ProvableHQ code subject to Apache 2.0 https://www.apache.org/licenses/LICENSE-2.0 13 // All modifications and new work: CC0 1.0 Universal Public Domain Dedication. 14 // No rights reserved. No permission required. No warranty. No refunds. 15 // 16 // https://creativecommons.org/publicdomain/zero/1.0/ 17 // SPDX-License-Identifier: CC0-1.0 18 19 pub const BECH32M_CHARSET: &str = "qpzry9x8gf2tvdw0s3jn54khce6mua7l1"; 20 21 /// Check if a string is a valid bech32m character set. 22 /// 23 /// A bech32m character set is considered valid if it consists of the following characters: 24 /// ```ignore 25 /// qpzry9x8gf2tvdw0s3jn54khce6mua7l1 26 /// ``` 27 /// The function returns `true` if the string is a valid bech32m character set, and `false` otherwise. 28 pub fn is_in_bech32m_charset(s: &str) -> bool { 29 s.as_bytes().iter().all(|b| BECH32M_CHARSET.as_bytes().contains(b)) 30 } 31 32 /// Check if a given vanity string exists at the start or end of the data part of a bech32m string. 33 /// 34 /// The bech32m string must have the following format: 35 /// ```ignore 36 /// <HRP>1<data>[<vanity string>] 37 /// ``` 38 /// where: 39 /// 40 /// - `<HRP>` is the human-readable part of the bech32m string. 41 /// - `1` is the separator between the HRP and the data part. 42 /// - `<data>` is the data part of the bech32m string. 43 /// - `<vanity string>` is the vanity string to search for. This string may or may not be present at 44 /// the start or end of the data part. 45 /// 46 /// The function returns `true` if the vanity string exists at the start or end of the data part, and 47 /// `false` otherwise. 48 pub fn has_vanity_string(s: &str, vanity: &str) -> bool { 49 // Split the bech32m string into the HRP and data parts. 50 let (hrp, data) = match s.split_once('1') { 51 Some((hrp, data)) => (hrp, data), 52 // The bech32m string is invalid. 53 None => return false, 54 }; 55 // Ensure neither the HRP nor the data part are empty. 56 if hrp.is_empty() || data.is_empty() { 57 return false; 58 } 59 // Check if the vanity string exists at the start or end of the data part. 60 data.starts_with(vanity) || data.ends_with(vanity) 61 } 62 63 #[test] 64 fn test_is_in_bech32m_charset() { 65 // Basic valid/invalid tests 66 assert!(is_in_bech32m_charset("qpzry9x8gf2tvdw0s3jn54khce6mua7l1qpzry9x8gf2tvdw0s3jn54khce6mua7l1")); 67 assert!(!is_in_bech32m_charset("qpzry9x8gf2tvdw0s3jn54khce6mua7l1qpzry9x8gf2tvdw0s3jn54khce6mua7lo")); 68 69 // Boundary: empty string should be valid (all() returns true for empty) 70 assert!(is_in_bech32m_charset("")); 71 72 // Single character tests - kills all->any mutation 73 assert!(is_in_bech32m_charset("q")); 74 assert!(!is_in_bech32m_charset("o")); 75 76 // Invalid character at different positions - kills boundary mutations 77 assert!(!is_in_bech32m_charset("oqqq")); // Invalid at start 78 assert!(!is_in_bech32m_charset("qqqo")); // Invalid at end 79 assert!(!is_in_bech32m_charset("qqoq")); // Invalid in middle 80 81 // All valid characters individually 82 for c in BECH32M_CHARSET.chars() { 83 assert!(is_in_bech32m_charset(&c.to_string())); 84 } 85 86 // Characters not in charset 87 assert!(!is_in_bech32m_charset("b")); // Lowercase not in set 88 assert!(!is_in_bech32m_charset("i")); // Excluded character 89 assert!(!is_in_bech32m_charset("O")); // Uppercase 90 } 91 92 #[test] 93 fn test_has_vanity_string() { 94 // Basic tests 95 assert!(has_vanity_string("myhrp1myvanitystring", "myvanitystring")); 96 assert!(!has_vanity_string("myhrp1myvanitystring", "anotherstring")); 97 assert!(has_vanity_string("myhrp1myvanitystring1234", "myvanitystring")); 98 assert!(has_vanity_string("myhrp11234myvanitystring", "myvanitystring")); 99 assert!(!has_vanity_string("myhrp1anotherstring1234", "myvanitystring")); 100 101 // Test starts_with specifically (kills || -> && mutation) 102 assert!(has_vanity_string("hrp1vanity", "vanity")); 103 assert!(has_vanity_string("hrp1vanityxxx", "vanity")); // starts_with only 104 105 // Test ends_with specifically (kills || -> && mutation) 106 assert!(has_vanity_string("hrp1xxxvanity", "vanity")); // ends_with only 107 108 // Test neither starts nor ends (ensures || logic is tested) 109 assert!(!has_vanity_string("hrp1xxvanityxx", "vanity")); 110 111 // Boundary: no separator - kills split_once mutation 112 assert!(!has_vanity_string("notseparated", "vanity")); 113 114 // Boundary: empty HRP - kills hrp.is_empty() mutation 115 assert!(!has_vanity_string("1data", "data")); 116 117 // Boundary: empty data - kills data.is_empty() mutation 118 assert!(!has_vanity_string("hrp1", "")); 119 120 // Boundary: empty vanity string (should match any data) 121 assert!(has_vanity_string("hrp1anydata", "")); 122 123 // Multiple separators - only first '1' is used 124 assert!(has_vanity_string("hrp11data", "1data")); 125 assert!(has_vanity_string("hrp1data1", "data1")); 126 127 // Vanity in middle only (not at start or end) 128 assert!(!has_vanity_string("hrp1aavanitybb", "vanity")); 129 }