bech32m.rs
1 // Copyright (c) 2025 ADnet Contributors 2 // This file is part of the AlphaOS library. 3 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at: 7 8 // http://www.apache.org/licenses/LICENSE-2.0 9 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 pub const BECH32M_CHARSET: &str = "qpzry9x8gf2tvdw0s3jn54khce6mua7l1"; 17 18 /// Check if a string is a valid bech32m character set. 19 /// 20 /// A bech32m character set is considered valid if it consists of the following characters: 21 /// ```ignore 22 /// qpzry9x8gf2tvdw0s3jn54khce6mua7l1 23 /// ``` 24 /// The function returns `true` if the string is a valid bech32m character set, and `false` otherwise. 25 pub fn is_in_bech32m_charset(s: &str) -> bool { 26 s.as_bytes().iter().all(|b| BECH32M_CHARSET.as_bytes().contains(b)) 27 } 28 29 /// Check if a given vanity string exists at the start or end of the data part of a bech32m string. 30 /// 31 /// The bech32m string must have the following format: 32 /// ```ignore 33 /// <HRP>1<data>[<vanity string>] 34 /// ``` 35 /// where: 36 /// 37 /// - `<HRP>` is the human-readable part of the bech32m string. 38 /// - `1` is the separator between the HRP and the data part. 39 /// - `<data>` is the data part of the bech32m string. 40 /// - `<vanity string>` is the vanity string to search for. This string may or may not be present at 41 /// the start or end of the data part. 42 /// 43 /// The function returns `true` if the vanity string exists at the start or end of the data part, and 44 /// `false` otherwise. 45 pub fn has_vanity_string(s: &str, vanity: &str) -> bool { 46 // Split the bech32m string into the HRP and data parts. 47 let (hrp, data) = match s.split_once('1') { 48 Some((hrp, data)) => (hrp, data), 49 // The bech32m string is invalid. 50 None => return false, 51 }; 52 // Ensure neither the HRP nor the data part are empty. 53 if hrp.is_empty() || data.is_empty() { 54 return false; 55 } 56 // Check if the vanity string exists at the start or end of the data part. 57 data.starts_with(vanity) || data.ends_with(vanity) 58 } 59 60 #[test] 61 fn test_is_in_bech32m_charset() { 62 assert!(is_in_bech32m_charset("qpzry9x8gf2tvdw0s3jn54khce6mua7l1qpzry9x8gf2tvdw0s3jn54khce6mua7l1")); 63 assert!(!is_in_bech32m_charset("qpzry9x8gf2tvdw0s3jn54khce6mua7l1qpzry9x8gf2tvdw0s3jn54khce6mua7lo")); 64 } 65 66 #[test] 67 fn test_has_vanity_string() { 68 assert!(has_vanity_string("myhrp1myvanitystring", "myvanitystring")); 69 assert!(!has_vanity_string("myhrp1myvanitystring", "anotherstring")); 70 assert!(has_vanity_string("myhrp1myvanitystring1234", "myvanitystring")); 71 assert!(has_vanity_string("myhrp11234myvanitystring", "myvanitystring")); 72 assert!(!has_vanity_string("myhrp1anotherstring1234", "myvanitystring")); 73 }