/ console / program / src / data / plaintext / mod.rs
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  }