parse.rs
1 // Copyright (c) 2019-2025 Alpha-Delta Network Inc. 2 // This file is part of the alphavm 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 use super::*; 17 18 static CIPHERTEXT_PREFIX: &str = "ciphertext"; 19 20 impl<N: Network> Parser for Ciphertext<N> { 21 /// Parses a string into an ciphertext. 22 #[inline] 23 fn parse(string: &str) -> ParserResult<Self> { 24 // Prepare a parser for the Alpha ciphertext. 25 let parse_ciphertext = recognize(pair( 26 pair(tag(CIPHERTEXT_PREFIX), tag("1")), 27 many1(terminated(one_of("qpzry9x8gf2tvdw0s3jn54khce6mua7l"), many0(char('_')))), 28 )); 29 30 // Parse the ciphertext from the string. 31 map_res(parse_ciphertext, |ciphertext: &str| -> Result<_, Error> { 32 Self::from_str(&ciphertext.replace('_', "")) 33 })(string) 34 } 35 } 36 37 impl<N: Network> FromStr for Ciphertext<N> { 38 type Err = Error; 39 40 /// Reads in the ciphertext string. 41 fn from_str(ciphertext: &str) -> Result<Self, Self::Err> { 42 // Decode the ciphertext string from bech32m. 43 let (hrp, data, variant) = bech32::decode(ciphertext)?; 44 if hrp != CIPHERTEXT_PREFIX { 45 bail!("Failed to decode ciphertext: '{hrp}' is an invalid prefix") 46 } else if data.is_empty() { 47 bail!("Failed to decode ciphertext: data field is empty") 48 } else if variant != bech32::Variant::Bech32m { 49 bail!("Found an ciphertext that is not bech32m encoded: {ciphertext}"); 50 } 51 // Decode the ciphertext data from u5 to u8, and into the ciphertext. 52 Ok(Self::read_le(&Vec::from_base32(&data)?[..])?) 53 } 54 } 55 56 impl<N: Network> Debug for Ciphertext<N> { 57 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 58 Display::fmt(self, f) 59 } 60 } 61 62 impl<N: Network> Display for Ciphertext<N> { 63 /// Writes the ciphertext as a bech32m string. 64 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 65 // Convert the ciphertext 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(CIPHERTEXT_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)] 76 mod tests { 77 use super::*; 78 use alphavm_console_network::MainnetV0; 79 80 type CurrentNetwork = MainnetV0; 81 82 const ITERATIONS: u64 = 1_000; 83 84 #[test] 85 fn test_parse() -> Result<()> { 86 // Ensure type and empty value fails. 87 assert!(Ciphertext::<CurrentNetwork>::parse(&format!("{CIPHERTEXT_PREFIX}1")).is_err()); 88 assert!(Ciphertext::<CurrentNetwork>::parse("").is_err()); 89 90 let mut rng = TestRng::default(); 91 92 for _ in 0..ITERATIONS { 93 // Sample a new ciphertext. 94 let ciphertext = 95 Ciphertext::<CurrentNetwork>((0..100).map(|_| Uniform::rand(&mut rng)).collect::<Vec<_>>()); 96 97 let expected = format!("{ciphertext}"); 98 let (remainder, candidate) = Ciphertext::<CurrentNetwork>::parse(&expected).unwrap(); 99 assert_eq!(format!("{expected}"), candidate.to_string()); 100 assert_eq!(CIPHERTEXT_PREFIX, candidate.to_string().split('1').next().unwrap()); 101 assert_eq!("", remainder); 102 } 103 Ok(()) 104 } 105 106 #[test] 107 fn test_string() -> Result<()> { 108 let mut rng = TestRng::default(); 109 110 for _ in 0..ITERATIONS { 111 // Sample a new ciphertext. 112 let expected = Ciphertext::<CurrentNetwork>((0..100).map(|_| Uniform::rand(&mut rng)).collect::<Vec<_>>()); 113 114 // Check the string representation. 115 let candidate = format!("{expected}"); 116 assert_eq!(expected, Ciphertext::from_str(&candidate)?); 117 assert_eq!(CIPHERTEXT_PREFIX, candidate.split('1').next().unwrap()); 118 } 119 Ok(()) 120 } 121 122 #[test] 123 fn test_display() -> Result<()> { 124 let mut rng = TestRng::default(); 125 126 for _ in 0..ITERATIONS { 127 // Sample a new ciphertext. 128 let expected = Ciphertext::<CurrentNetwork>((0..100).map(|_| Uniform::rand(&mut rng)).collect::<Vec<_>>()); 129 130 let candidate = expected.to_string(); 131 assert_eq!(format!("{expected}"), candidate); 132 assert_eq!(CIPHERTEXT_PREFIX, candidate.split('1').next().unwrap()); 133 134 let candidate_recovered = Ciphertext::<CurrentNetwork>::from_str(&candidate.to_string())?; 135 assert_eq!(expected, candidate_recovered); 136 } 137 Ok(()) 138 } 139 }