mod.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 mod bytes; 17 mod encrypt; 18 mod equal; 19 mod find; 20 mod from_bits; 21 mod from_fields; 22 mod num_randomizers; 23 mod parse; 24 mod serialize; 25 mod size_in_fields; 26 mod to_bits; 27 mod to_bits_raw; 28 mod to_fields; 29 mod to_fields_raw; 30 31 use crate::{Access, Ciphertext, Identifier, Literal, PlaintextType}; 32 use alphavm_console_network::Network; 33 use alphavm_console_types::prelude::*; 34 35 use indexmap::IndexMap; 36 use std::sync::OnceLock; 37 38 #[derive(Clone)] 39 pub enum Plaintext<N: Network> { 40 /// A literal. 41 Literal(Literal<N>, OnceLock<Vec<bool>>), 42 /// A struct. 43 Struct(IndexMap<Identifier<N>, Plaintext<N>>, OnceLock<Vec<bool>>), 44 /// An array. 45 Array(Vec<Plaintext<N>>, OnceLock<Vec<bool>>), 46 } 47 48 impl<N: Network> Plaintext<N> { 49 /// Returns a new `Plaintext::Array` from `Vec<bool>`, checking that the length is correct. 50 pub fn from_bit_array(bits: Vec<bool>, length: u32) -> Result<Self> { 51 ensure!(bits.len() == length as usize, "Expected '{length}' bits, got '{}' bits", bits.len()); 52 Ok(Self::Array( 53 bits.into_iter().map(|bit| Plaintext::from(Literal::Boolean(Boolean::new(bit)))).collect(), 54 OnceLock::new(), 55 )) 56 } 57 58 /// Returns the `Plaintext` as a `Vec<bool>`, if it is a bit array. 59 pub fn as_bit_array(&self) -> Result<Vec<bool>> { 60 match self { 61 Self::Array(elements, _) => { 62 let mut bits = Vec::with_capacity(elements.len()); 63 for element in elements { 64 match element { 65 Self::Literal(Literal::Boolean(bit), _) => bits.push(**bit), 66 _ => bail!("Expected a bit array, found a non-boolean element."), 67 } 68 } 69 Ok(bits) 70 } 71 _ => bail!("Expected a bit array, found a non-array plaintext."), 72 } 73 } 74 } 75 76 impl<N: Network> From<Literal<N>> for Plaintext<N> { 77 /// Returns a new `Plaintext` from a `Literal`. 78 fn from(literal: Literal<N>) -> Self { 79 Self::Literal(literal, OnceLock::new()) 80 } 81 } 82 83 impl<N: Network> From<&Literal<N>> for Plaintext<N> { 84 /// Returns a new `Plaintext` from a `&Literal`. 85 fn from(literal: &Literal<N>) -> Self { 86 Self::Literal(literal.clone(), OnceLock::new()) 87 } 88 } 89 90 // A macro that derives implementations of `From` for arrays of a plaintext literals of various sizes. 91 macro_rules! impl_plaintext_from_array { 92 ($element:ident, $($size:literal),+) => { 93 $( 94 impl<N: Network> From<[$element<N>; $size]> for Plaintext<N> { 95 fn from(value: [$element<N>; $size]) -> Self { 96 Self::Array( 97 value 98 .into_iter() 99 .map(|element| Plaintext::from(Literal::$element(element))) 100 .collect(), 101 OnceLock::new(), 102 ) 103 } 104 } 105 )+ 106 }; 107 } 108 109 // Implement for `[U8<N>, SIZE]` for sizes 1 through 256. 110 seq_macro::seq!(S in 1..=256 { 111 impl_plaintext_from_array!(U8, S); 112 }); 113 114 #[cfg(test)] 115 mod tests { 116 use super::*; 117 use alphavm_console_network::MainnetV0; 118 use alphavm_console_types::Field; 119 120 use core::str::FromStr; 121 122 type CurrentNetwork = MainnetV0; 123 124 #[test] 125 fn test_plaintext() -> Result<()> { 126 let run_test = |value: Plaintext<CurrentNetwork>| { 127 assert_eq!( 128 value.to_bits_le(), 129 Plaintext::<CurrentNetwork>::from_bits_le(&value.to_bits_le()).unwrap().to_bits_le() 130 ); 131 assert_eq!(value, Plaintext::<CurrentNetwork>::from_fields(&value.to_fields().unwrap()).unwrap()); 132 assert_eq!(value, Plaintext::<CurrentNetwork>::from_str(&value.to_string()).unwrap()); 133 assert!(*value.is_equal(&value)); 134 assert!(*!value.is_not_equal(&value)); 135 }; 136 137 let mut rng = TestRng::default(); 138 139 // Test booleans. 140 run_test(Plaintext::<CurrentNetwork>::from_str("true")?); 141 run_test(Plaintext::<CurrentNetwork>::from_str("false")?); 142 143 // Test a random field element. 144 run_test(Plaintext::<CurrentNetwork>::Literal( 145 Literal::Field(Field::new(Uniform::rand(&mut rng))), 146 OnceLock::new(), 147 )); 148 149 // Test a random struct with literal members. 150 run_test(Plaintext::<CurrentNetwork>::Struct( 151 IndexMap::from_iter(vec![ 152 (Identifier::from_str("a")?, Plaintext::<CurrentNetwork>::from_str("true")?), 153 ( 154 Identifier::from_str("b")?, 155 Plaintext::<CurrentNetwork>::Literal( 156 Literal::Field(Field::new(Uniform::rand(&mut rng))), 157 OnceLock::new(), 158 ), 159 ), 160 ]), 161 OnceLock::new(), 162 )); 163 164 // Test a random struct with array members. 165 run_test(Plaintext::<CurrentNetwork>::Struct( 166 IndexMap::from_iter(vec![ 167 (Identifier::from_str("a")?, Plaintext::<CurrentNetwork>::from_str("true")?), 168 ( 169 Identifier::from_str("b")?, 170 Plaintext::<CurrentNetwork>::Array( 171 vec![ 172 Plaintext::<CurrentNetwork>::from_str("true")?, 173 Plaintext::<CurrentNetwork>::from_str("false")?, 174 ], 175 OnceLock::new(), 176 ), 177 ), 178 ]), 179 OnceLock::new(), 180 )); 181 182 // Test random deeply-nested struct. 183 run_test(Plaintext::<CurrentNetwork>::Struct( 184 IndexMap::from_iter(vec![ 185 (Identifier::from_str("a")?, Plaintext::<CurrentNetwork>::from_str("true")?), 186 ( 187 Identifier::from_str("b")?, 188 Plaintext::<CurrentNetwork>::Struct( 189 IndexMap::from_iter(vec![ 190 (Identifier::from_str("c")?, Plaintext::<CurrentNetwork>::from_str("true")?), 191 ( 192 Identifier::from_str("d")?, 193 Plaintext::<CurrentNetwork>::Struct( 194 IndexMap::from_iter(vec![ 195 (Identifier::from_str("e")?, Plaintext::<CurrentNetwork>::from_str("true")?), 196 ( 197 Identifier::from_str("f")?, 198 Plaintext::<CurrentNetwork>::Literal( 199 Literal::Field(Field::new(Uniform::rand(&mut rng))), 200 OnceLock::new(), 201 ), 202 ), 203 ]), 204 OnceLock::new(), 205 ), 206 ), 207 ( 208 Identifier::from_str("g")?, 209 Plaintext::Array( 210 vec![ 211 Plaintext::<CurrentNetwork>::from_str("true")?, 212 Plaintext::<CurrentNetwork>::from_str("false")?, 213 ], 214 OnceLock::new(), 215 ), 216 ), 217 ]), 218 OnceLock::new(), 219 ), 220 ), 221 ( 222 Identifier::from_str("h")?, 223 Plaintext::<CurrentNetwork>::Literal( 224 Literal::Field(Field::new(Uniform::rand(&mut rng))), 225 OnceLock::new(), 226 ), 227 ), 228 ]), 229 OnceLock::new(), 230 )); 231 232 // Test an array of literals. 233 run_test(Plaintext::<CurrentNetwork>::Array( 234 vec![ 235 Plaintext::<CurrentNetwork>::from_str("0field")?, 236 Plaintext::<CurrentNetwork>::from_str("1field")?, 237 Plaintext::<CurrentNetwork>::from_str("2field")?, 238 Plaintext::<CurrentNetwork>::from_str("3field")?, 239 Plaintext::<CurrentNetwork>::from_str("4field")?, 240 ], 241 OnceLock::new(), 242 )); 243 244 // Test an array of structs. 245 run_test(Plaintext::<CurrentNetwork>::Array( 246 vec![ 247 Plaintext::<CurrentNetwork>::from_str("{ x: 0field, y: 1field }")?, 248 Plaintext::<CurrentNetwork>::from_str("{ x: 2field, y: 3field }")?, 249 Plaintext::<CurrentNetwork>::from_str("{ x: 4field, y: 5field }")?, 250 Plaintext::<CurrentNetwork>::from_str("{ x: 6field, y: 7field }")?, 251 Plaintext::<CurrentNetwork>::from_str("{ x: 8field, y: 9field }")?, 252 ], 253 OnceLock::new(), 254 )); 255 256 // Test a non-uniform array. 257 run_test(Plaintext::<CurrentNetwork>::Array( 258 vec![ 259 Plaintext::<CurrentNetwork>::from_str("true")?, 260 Plaintext::<CurrentNetwork>::from_str("1field")?, 261 Plaintext::<CurrentNetwork>::from_str("{ x: 4field, y: 1u8 }")?, 262 ], 263 OnceLock::new(), 264 )); 265 266 Ok(()) 267 } 268 }