/ circuit / program / src / data / plaintext / mod.rs
mod.rs
  1  // Copyright (c) 2019-2025 Alpha-Delta Network Inc.
  2  // This file is part of the deltavm 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 std::cell::OnceCell;
 17  
 18  #[cfg(test)]
 19  use deltavm_circuit_types::environment::assert_scope;
 20  
 21  mod encrypt;
 22  mod equal;
 23  mod find;
 24  mod from_bits;
 25  mod from_fields;
 26  mod num_randomizers;
 27  mod size_in_fields;
 28  mod to_bits;
 29  mod to_bits_raw;
 30  mod to_fields;
 31  mod to_fields_raw;
 32  
 33  use crate::{Access, Ciphertext, Identifier, Literal, Visibility};
 34  use deltavm_circuit_network::Alpha;
 35  use deltavm_circuit_types::{Address, Boolean, Field, Scalar, U8, U16, U32, environment::prelude::*};
 36  use console::PlaintextType;
 37  
 38  #[derive(Clone)]
 39  pub enum Plaintext<A: Alpha> {
 40      /// A plaintext literal.
 41      Literal(Literal<A>, OnceCell<Vec<Boolean<A>>>),
 42      /// A plaintext struct.
 43      Struct(IndexMap<Identifier<A>, Plaintext<A>>, OnceCell<Vec<Boolean<A>>>),
 44      /// A plaintext array.
 45      Array(Vec<Plaintext<A>>, OnceCell<Vec<Boolean<A>>>),
 46  }
 47  
 48  impl<A: Alpha> Plaintext<A> {
 49      /// Returns a new `Plaintext::Array` from `Vec<Boolean<A>>`, checking that the length is correct.
 50      pub fn from_bit_array(bits: Vec<Boolean<A>>, length: u32) -> Result<Self> {
 51          ensure!(bits.len() == length as usize, "Expected '{length}' bits, got '{}' bits", bits.len());
 52          Ok(Self::Array(bits.into_iter().map(|bit| Plaintext::from(Literal::Boolean(bit))).collect(), OnceCell::new()))
 53      }
 54  
 55      /// Returns the `Plaintext` as a `Vec<Boolean<A>>`, if it is a bit array.
 56      pub fn as_bit_array(&self) -> Result<Vec<Boolean<A>>> {
 57          match self {
 58              Self::Array(elements, _) => {
 59                  let mut bits = Vec::with_capacity(elements.len());
 60                  for element in elements {
 61                      match element {
 62                          Self::Literal(Literal::Boolean(bit), _) => bits.push(bit.clone()),
 63                          _ => bail!("Expected a bit array, found a non-boolean element."),
 64                      }
 65                  }
 66                  Ok(bits)
 67              }
 68              _ => bail!("Expected a bit array, found a non-array plaintext."),
 69          }
 70      }
 71  }
 72  
 73  impl<A: Alpha> Inject for Plaintext<A> {
 74      type Primitive = console::Plaintext<A::Network>;
 75  
 76      /// Initializes a new plaintext circuit from a primitive.
 77      fn new(mode: Mode, plaintext: Self::Primitive) -> Self {
 78          match plaintext {
 79              Self::Primitive::Literal(literal, _) => Self::Literal(Literal::new(mode, literal), Default::default()),
 80              Self::Primitive::Struct(struct_, _) => Self::Struct(Inject::new(mode, struct_), Default::default()),
 81              Self::Primitive::Array(array, _) => Self::Array(Inject::new(mode, array), Default::default()),
 82          }
 83      }
 84  }
 85  
 86  impl<A: Alpha> Eject for Plaintext<A> {
 87      type Primitive = console::Plaintext<A::Network>;
 88  
 89      /// Ejects the mode of the plaintext value.
 90      fn eject_mode(&self) -> Mode {
 91          match self {
 92              Self::Literal(literal, _) => literal.eject_mode(),
 93              Self::Struct(struct_, _) => struct_
 94                  .iter()
 95                  .map(|(identifier, value)| (identifier, value).eject_mode())
 96                  .collect::<Vec<_>>()
 97                  .eject_mode(),
 98              Self::Array(array, _) => array.iter().map(Eject::eject_mode).collect::<Vec<_>>().eject_mode(),
 99          }
100      }
101  
102      /// Ejects the plaintext value.
103      fn eject_value(&self) -> Self::Primitive {
104          match self {
105              Self::Literal(literal, _) => console::Plaintext::Literal(literal.eject_value(), Default::default()),
106              Self::Struct(struct_, _) => {
107                  console::Plaintext::Struct(struct_.iter().map(|pair| pair.eject_value()).collect(), Default::default())
108              }
109              Self::Array(array, _) => {
110                  console::Plaintext::Array(array.iter().map(Eject::eject_value).collect(), Default::default())
111              }
112          }
113      }
114  }
115  
116  impl<A: Alpha> From<Literal<A>> for Plaintext<A> {
117      /// Returns a new `Plaintext` from a `Literal`.
118      fn from(literal: Literal<A>) -> Self {
119          Self::Literal(literal, OnceCell::new())
120      }
121  }
122  
123  impl<A: Alpha> From<&Literal<A>> for Plaintext<A> {
124      /// Returns a new `Plaintext` from a `Literal`.
125      fn from(literal: &Literal<A>) -> Self {
126          Self::Literal((*literal).clone(), OnceCell::new())
127      }
128  }
129  
130  // A macro that derives implementations of `From` for arrays of a plaintext literals of various sizes.
131  macro_rules! impl_plaintext_from_array {
132      ($element:ident, $($size:literal),+) => {
133          $(
134              impl<A: Alpha> From<[$element<A>; $size]> for Plaintext<A> {
135                  fn from(value: [$element<A>; $size]) -> Self {
136                      Self::Array(
137                          value
138                              .into_iter()
139                              .map(|element| Plaintext::from(Literal::$element(element)))
140                              .collect(),
141                          OnceCell::new(),
142                      )
143                  }
144              }
145          )+
146      };
147  }
148  
149  // Implement for `[U8<N>, SIZE]` for sizes 1 through 32.
150  impl_plaintext_from_array!(
151      U8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
152      31, 32
153  );
154  
155  #[cfg(test)]
156  mod tests {
157      use super::*;
158      use crate::Circuit;
159      use deltavm_utilities::{TestRng, Uniform};
160  
161      use anyhow::Result;
162  
163      #[test]
164      fn test_plaintext() -> Result<()> {
165          let run_test = |value: Plaintext<Circuit>| {
166              assert_eq!(
167                  value.to_bits_le().eject(),
168                  Plaintext::<Circuit>::from_bits_le(&value.to_bits_le()).to_bits_le().eject()
169              );
170              assert_eq!(value.eject(), Plaintext::<Circuit>::from_fields(&value.to_fields()).eject());
171              assert!(value.is_equal(&value).eject_value());
172              assert!(!value.is_not_equal(&value).eject_value());
173          };
174  
175          let mut rng = TestRng::default();
176  
177          // Test booleans.
178          run_test(Plaintext::<Circuit>::Literal(Literal::Boolean(Boolean::new(Mode::Private, true)), OnceCell::new()));
179          run_test(Plaintext::<Circuit>::Literal(Literal::Boolean(Boolean::new(Mode::Private, false)), OnceCell::new()));
180  
181          // Test a random field element.
182          run_test(Plaintext::<Circuit>::Literal(
183              Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
184              OnceCell::new(),
185          ));
186  
187          // Test a random struct with literal members.
188          run_test(Plaintext::<Circuit>::Struct(
189              IndexMap::from_iter(vec![
190                  (
191                      Identifier::new(Mode::Private, "a".try_into()?),
192                      Plaintext::<Circuit>::Literal(Literal::Boolean(Boolean::new(Mode::Private, true)), OnceCell::new()),
193                  ),
194                  (
195                      Identifier::new(Mode::Private, "b".try_into()?),
196                      Plaintext::<Circuit>::Literal(
197                          Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
198                          OnceCell::new(),
199                      ),
200                  ),
201              ]),
202              OnceCell::new(),
203          ));
204  
205          // Test a random struct with array members.
206          run_test(Plaintext::<Circuit>::Struct(
207              IndexMap::from_iter(vec![
208                  (
209                      Identifier::new(Mode::Private, "a".try_into()?),
210                      Plaintext::<Circuit>::Literal(Literal::Boolean(Boolean::new(Mode::Private, true)), OnceCell::new()),
211                  ),
212                  (
213                      Identifier::new(Mode::Private, "b".try_into()?),
214                      Plaintext::<Circuit>::Array(
215                          vec![
216                              Plaintext::<Circuit>::Literal(
217                                  Literal::Boolean(Boolean::new(Mode::Private, true)),
218                                  OnceCell::new(),
219                              ),
220                              Plaintext::<Circuit>::Literal(
221                                  Literal::Boolean(Boolean::new(Mode::Private, false)),
222                                  OnceCell::new(),
223                              ),
224                          ],
225                          OnceCell::new(),
226                      ),
227                  ),
228              ]),
229              OnceCell::new(),
230          ));
231  
232          // Test random deeply-nested struct.
233          run_test(Plaintext::<Circuit>::Struct(
234              IndexMap::from_iter(vec![
235                  (
236                      Identifier::new(Mode::Private, "a".try_into()?),
237                      Plaintext::<Circuit>::Literal(Literal::Boolean(Boolean::new(Mode::Private, true)), OnceCell::new()),
238                  ),
239                  (
240                      Identifier::new(Mode::Private, "b".try_into()?),
241                      Plaintext::<Circuit>::Struct(
242                          IndexMap::from_iter(vec![
243                              (
244                                  Identifier::new(Mode::Private, "c".try_into()?),
245                                  Plaintext::<Circuit>::Literal(
246                                      Literal::Boolean(Boolean::new(Mode::Private, true)),
247                                      OnceCell::new(),
248                                  ),
249                              ),
250                              (
251                                  Identifier::new(Mode::Private, "d".try_into()?),
252                                  Plaintext::<Circuit>::Struct(
253                                      IndexMap::from_iter(vec![
254                                          (
255                                              Identifier::new(Mode::Private, "e".try_into()?),
256                                              Plaintext::<Circuit>::Literal(
257                                                  Literal::Boolean(Boolean::new(Mode::Private, true)),
258                                                  OnceCell::new(),
259                                              ),
260                                          ),
261                                          (
262                                              Identifier::new(Mode::Private, "f".try_into()?),
263                                              Plaintext::<Circuit>::Literal(
264                                                  Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
265                                                  OnceCell::new(),
266                                              ),
267                                          ),
268                                      ]),
269                                      OnceCell::new(),
270                                  ),
271                              ),
272                              (
273                                  Identifier::new(Mode::Private, "g".try_into()?),
274                                  Plaintext::<Circuit>::Array(
275                                      vec![
276                                          Plaintext::<Circuit>::Literal(
277                                              Literal::Boolean(Boolean::new(Mode::Private, true)),
278                                              OnceCell::new(),
279                                          ),
280                                          Plaintext::<Circuit>::Literal(
281                                              Literal::Boolean(Boolean::new(Mode::Private, false)),
282                                              OnceCell::new(),
283                                          ),
284                                      ],
285                                      OnceCell::new(),
286                                  ),
287                              ),
288                          ]),
289                          OnceCell::new(),
290                      ),
291                  ),
292                  (
293                      Identifier::new(Mode::Private, "h".try_into()?),
294                      Plaintext::<Circuit>::Literal(
295                          Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
296                          OnceCell::new(),
297                      ),
298                  ),
299              ]),
300              OnceCell::new(),
301          ));
302  
303          // Test an array of literals.
304          run_test(Plaintext::<Circuit>::Array(
305              vec![
306                  Plaintext::<Circuit>::Literal(
307                      Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
308                      OnceCell::new(),
309                  ),
310                  Plaintext::<Circuit>::Literal(
311                      Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
312                      OnceCell::new(),
313                  ),
314                  Plaintext::<Circuit>::Literal(
315                      Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
316                      OnceCell::new(),
317                  ),
318                  Plaintext::<Circuit>::Literal(
319                      Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
320                      OnceCell::new(),
321                  ),
322                  Plaintext::<Circuit>::Literal(
323                      Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
324                      OnceCell::new(),
325                  ),
326              ],
327              OnceCell::new(),
328          ));
329  
330          // Test an array of structs.
331          run_test(Plaintext::<Circuit>::Array(
332              vec![
333                  Plaintext::<Circuit>::Struct(
334                      IndexMap::from_iter(vec![
335                          (
336                              Identifier::new(Mode::Private, "x".try_into()?),
337                              Plaintext::<Circuit>::Literal(
338                                  Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
339                                  OnceCell::new(),
340                              ),
341                          ),
342                          (
343                              Identifier::new(Mode::Private, "y".try_into()?),
344                              Plaintext::<Circuit>::Literal(
345                                  Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
346                                  OnceCell::new(),
347                              ),
348                          ),
349                      ]),
350                      OnceCell::new(),
351                  ),
352                  Plaintext::<Circuit>::Struct(
353                      IndexMap::from_iter(vec![
354                          (
355                              Identifier::new(Mode::Private, "x".try_into()?),
356                              Plaintext::<Circuit>::Literal(
357                                  Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
358                                  OnceCell::new(),
359                              ),
360                          ),
361                          (
362                              Identifier::new(Mode::Private, "y".try_into()?),
363                              Plaintext::<Circuit>::Literal(
364                                  Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
365                                  OnceCell::new(),
366                              ),
367                          ),
368                      ]),
369                      OnceCell::new(),
370                  ),
371                  Plaintext::<Circuit>::Struct(
372                      IndexMap::from_iter(vec![
373                          (
374                              Identifier::new(Mode::Private, "x".try_into()?),
375                              Plaintext::<Circuit>::Literal(
376                                  Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
377                                  OnceCell::new(),
378                              ),
379                          ),
380                          (
381                              Identifier::new(Mode::Private, "y".try_into()?),
382                              Plaintext::<Circuit>::Literal(
383                                  Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
384                                  OnceCell::new(),
385                              ),
386                          ),
387                      ]),
388                      OnceCell::new(),
389                  ),
390              ],
391              OnceCell::new(),
392          ));
393  
394          // Test a non-uniform array.
395          run_test(Plaintext::<Circuit>::Array(
396              vec![
397                  Plaintext::<Circuit>::Literal(Literal::Boolean(Boolean::new(Mode::Private, true)), OnceCell::new()),
398                  Plaintext::<Circuit>::Literal(
399                      Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
400                      OnceCell::new(),
401                  ),
402                  Plaintext::<Circuit>::Struct(
403                      IndexMap::from_iter(vec![
404                          (
405                              Identifier::new(Mode::Private, "x".try_into()?),
406                              Plaintext::<Circuit>::Literal(
407                                  Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
408                                  OnceCell::new(),
409                              ),
410                          ),
411                          (
412                              Identifier::new(Mode::Private, "y".try_into()?),
413                              Plaintext::<Circuit>::Literal(
414                                  Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
415                                  OnceCell::new(),
416                              ),
417                          ),
418                      ]),
419                      OnceCell::new(),
420                  ),
421              ],
422              OnceCell::new(),
423          ));
424  
425          Ok(())
426      }
427  }