snarkvm_synthesizer_snark/certificate/
parse.rs

1// Copyright (c) 2019-2025 Provable Inc.
2// This file is part of the snarkVM 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
16use super::*;
17
18static PROOF_PREFIX: &str = "certificate";
19
20impl<N: Network> Parser for Certificate<N> {
21    /// Parses a string into an certificate.
22    #[inline]
23    fn parse(string: &str) -> ParserResult<Self> {
24        // Prepare a parser for the Aleo certificate.
25        let parse_certificate = recognize(pair(
26            pair(tag(PROOF_PREFIX), tag("1")),
27            many1(terminated(one_of("qpzry9x8gf2tvdw0s3jn54khce6mua7l"), many0(char('_')))),
28        ));
29
30        // Parse the certificate from the string.
31        map_res(parse_certificate, |certificate: &str| -> Result<_, Error> {
32            Self::from_str(&certificate.replace('_', ""))
33        })(string)
34    }
35}
36
37impl<N: Network> FromStr for Certificate<N> {
38    type Err = Error;
39
40    /// Reads in the certificate string.
41    fn from_str(certificate: &str) -> Result<Self, Self::Err> {
42        // Decode the certificate string from bech32m.
43        let (hrp, data, variant) = bech32::decode(certificate)?;
44        if hrp != PROOF_PREFIX {
45            bail!("Failed to decode certificate: '{hrp}' is an invalid prefix")
46        } else if data.is_empty() {
47            bail!("Failed to decode certificate: data field is empty")
48        } else if variant != bech32::Variant::Bech32m {
49            bail!("Found an certificate that is not bech32m encoded: {certificate}");
50        }
51        // Decode the certificate data from u5 to u8, and into the certificate.
52        Ok(Self::read_le(&Vec::from_base32(&data)?[..])?)
53    }
54}
55
56impl<N: Network> Debug for Certificate<N> {
57    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
58        Display::fmt(self, f)
59    }
60}
61
62impl<N: Network> Display for Certificate<N> {
63    /// Writes the certificate as a bech32m string.
64    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
65        // Convert the certificate to bytes.
66        let bytes = self.to_bytes_le().map_err(|_| fmt::Error)?;
67        // Encode the bytes into bech32m.
68        let string =
69            bech32::encode(PROOF_PREFIX, bytes.to_base32(), bech32::Variant::Bech32m).map_err(|_| fmt::Error)?;
70        // Output the string.
71        Display::fmt(&string, f)
72    }
73}
74
75#[cfg(test)]
76mod tests {
77    use super::*;
78    use console::network::MainnetV0;
79
80    type CurrentNetwork = MainnetV0;
81
82    #[test]
83    fn test_parse() -> Result<()> {
84        // Ensure type and empty value fails.
85        assert!(Certificate::<CurrentNetwork>::parse(&format!("{PROOF_PREFIX}1")).is_err());
86        assert!(Certificate::<CurrentNetwork>::parse("").is_err());
87
88        // Sample the certificate.
89        let certificate = crate::test_helpers::sample_certificate();
90
91        // Check the certificate parsing.
92        let expected = format!("{certificate}");
93        let (remainder, candidate) = Certificate::<CurrentNetwork>::parse(&expected).unwrap();
94        assert_eq!(format!("{expected}"), candidate.to_string());
95        assert_eq!(PROOF_PREFIX, candidate.to_string().split('1').next().unwrap());
96        assert_eq!("", remainder);
97        Ok(())
98    }
99
100    #[test]
101    fn test_string() -> Result<()> {
102        // Sample the certificate.
103        let expected = crate::test_helpers::sample_certificate();
104
105        // Check the string representation.
106        let candidate = format!("{expected}");
107        assert_eq!(expected, Certificate::from_str(&candidate)?);
108        assert_eq!(PROOF_PREFIX, candidate.split('1').next().unwrap());
109
110        Ok(())
111    }
112
113    #[test]
114    fn test_display() -> Result<()> {
115        // Sample the certificate.
116        let expected = crate::test_helpers::sample_certificate();
117
118        let candidate = expected.to_string();
119        assert_eq!(format!("{expected}"), candidate);
120        assert_eq!(PROOF_PREFIX, candidate.split('1').next().unwrap());
121
122        let candidate_recovered = Certificate::<CurrentNetwork>::from_str(&candidate)?;
123        assert_eq!(expected, candidate_recovered);
124
125        Ok(())
126    }
127}