snarkvm_circuit_program/data/plaintext/
mod.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 std::cell::OnceCell;
17
18#[cfg(test)]
19use snarkvm_circuit_types::environment::assert_scope;
20
21mod encrypt;
22mod equal;
23mod find;
24mod from_bits;
25mod from_fields;
26mod num_randomizers;
27mod size_in_fields;
28mod to_bits;
29mod to_bits_raw;
30mod to_fields;
31mod to_fields_raw;
32
33use crate::{Access, Ciphertext, Identifier, Literal, Visibility};
34use console::PlaintextType;
35use snarkvm_circuit_network::Aleo;
36use snarkvm_circuit_types::{Address, Boolean, Field, Scalar, U8, U16, U32, environment::prelude::*};
37
38#[derive(Clone)]
39pub enum Plaintext<A: Aleo> {
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
48impl<A: Aleo> 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
73impl<A: Aleo> 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
86impl<A: Aleo> 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
116impl<A: Aleo> 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
123impl<A: Aleo> 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.
131macro_rules! impl_plaintext_from_array {
132    ($element:ident, $($size:literal),+) => {
133        $(
134            impl<A: Aleo> 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.
150impl_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)]
156mod tests {
157    use super::*;
158    use crate::Circuit;
159    use snarkvm_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}