snarkos_cli/helpers/
bech32m.rs

1// Copyright 2024 Aleo Network Foundation
2// This file is part of the snarkOS 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
16pub 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.
25pub 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.
45pub 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]
61fn test_is_in_bech32m_charset() {
62    assert!(is_in_bech32m_charset("qpzry9x8gf2tvdw0s3jn54khce6mua7l1qpzry9x8gf2tvdw0s3jn54khce6mua7l1"));
63    assert!(!is_in_bech32m_charset("qpzry9x8gf2tvdw0s3jn54khce6mua7l1qpzry9x8gf2tvdw0s3jn54khce6mua7lo"));
64}
65
66#[test]
67fn 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}